所有談到的JSF定製標記庫都是不錯的,但是,如果我有自己的定製標記,或有第三方的標記庫應該怎麼辦?或者我要使用JSP標準標記庫 (JSTL)?它是一組能做我們剛提到的所有事情的標記庫。 在極大程度上,這些標記能與JSF標記混合使用。 Faces標記能在其它標記的內部嵌套使用,反之亦然。 一些產品,象IBM的 WebSphere Application Developer, 鼓勵這種方法。其它的如 Sun的 Java Creator Studio則選擇純的JSF標記, 另一方面,Oracle的 JDeveloper 讓你混合和配合使用,但也鼓勵使用純JSF標記。
注意: 無論何時,你將JSF 標記嵌套在非JSF定製標記內時,你必須指派一個組件標識符到JSF 標記。 因為JSTL 是標準的並且許多人熟悉它,我們將用它示範如何將它與 JSF定製標記一起使用。 (如果你想全面瞭解JSTL, 請看 Shawn Bayern寫的一本極好的書, JSTL in Action.) 讓我們從簡單的例子開始 (顯示在清單1) JSTL 標記和 JSF 標記混合和配合使用。代碼引入了兩個 JSF 標記庫和核心 JSTL 標記庫。
清單 1. JSTL 標記與 JSF 標記混合使用
代碼內容
代碼內容 <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html> <head> <title>JSF in Action: JSTL Example 1 - Mixing JSF with other custom tags</title> </head> <body bgcolor="#FFFFFF"> <f:view> <h1> <h:outputText value="Example of using JSF tags with other custom tags"/> </h1> <p> <b> <c:out value="Here’s the value of your web.xml (don’t do this at home):"/> </b> <blockquote> <f:verbatim> <c:import url="WEB-INF/web.xml"/> </f:verbatim> </blockquote> </p> </f:view> </body> </html></code> |
在這個例子裡, JSTL 和JSF 標記嵌套在 JSF標記 <f:view>內, <f:view>定義了JSF組件樹的開始。這個例子使用了 JSF 的h標記 (<h:outputText>) 和JSTL <c:out> 標記顯示文本。 在這個頁面內,JSTL <c:import> 標記包含系統的 web.xml 檔案 (這不是你想與其它人共用檔案的正確方法,所以,不要在一台真實的伺服器上這樣做). 因為 web.xml 是一個XML 檔案, <c:import>標記要嵌套在<f:verbatim> 內, <f:verbatim>是一個 JSF UIOutput組件並且繪製時轉義XML元素,所以能在HTML頁內正確顯示。這個例子沒有太多的內容,但它示範了在同一頁面內不同的標記能一起使用。注意我們把JSTL 標記嵌套在 JSF <f:verbatim> 標記內,一般而言,它比將 JSF 標記嵌套在其它標記內容易。事實上,任何有子組件的組件如 HtmlDataTable和 HtmlPanelGrid需要將模板文本嵌套在一個<f:verbatim> 標記內。 JSTL 標記與 JSF 標記一起使用使JSF變得更強大,這兩者都使用類似的運算式語言。 (對 JSP 2.0’s 運算式也是如此l). 這允許你以一種直觀的方式在JSTL 和 JSF 標記間共用資料。 這裡舉例說明這一點,讓我們看另一個例子, 它允許使用者在 HtmlInputText 控制項中輸入一個值,然後利用這個值用 JSTL <c:forEach>標記重複輸出一個字串。 代碼在清單2列出。
清單2. JSF 、JSTL 標記和同一個 backing bean
代碼內容
代碼內容 ... <f:view> <jsp:useBean class="org.jia.examples.TestForm" id="exampleBean" scope="session"/> <h1> <h:outputText value="Example of using JSF and JSTL expression languages"/> </h1> <h:form> <h:outputLabel for="inputInt"> <h:outputText value="How many times do you want to repeat the Oracle’s prophecy?"/> </h:outputLabel> <h:inputText id="inputInt" value="#{sessionScope.exampleBean.number}"/> <h:commandButton value="Go!"/> <p> <c:if test="${sessionScope.exampleBean.number > 0}"> <c:forEach begin="0" end="${sessionScope.exampleBean.number - 1}" var="count"> Queen Tracey will achieve world domination.<br> </c:forEach> </c:if> </p> </h:form> ... </f:view> ... |
警告: 如果你用 JSP 或 JSTL 運算式訪問 managed beans, 你必須確保 beans 已經被建立,這是因為這些舊的運算式語言不知道JSF中的Managed Bean如何建立。這個例子中定義了一個叫exampleBean的JavaBean, 它有一個int類型的 number 屬性。使用HtmlInputText 組件基於使用者的輸入更新bean的屬性值。當使用者點擊Go! 按鈕時 (一個 HtmlCommandButton 組件), 更新number屬性的值並重新顯示頁面。 當這一切發生時, JSTL <c:forEach> 標記通過 JSTL <c:out> 標記重複顯示文本 exampleBean.number 次。當exampleBean.number的值大於0時,<c:forEach> 標記才執行,這通過JSTL <c:if>進行測試。
你不能在疊代主體的迴圈標記內部使用 JSF 組件標記,象JSTL 的 <c:forEach>標記。 推薦的方法是使用 HtmlDataTable 組件或其它的組件疊代一個資料集或集合,在這個例子中,沒有 JSF 組件 嵌套在 JSTL <c:if>標記內。 但是如果組件顯示一次然後當頁面再次顯示時被條件標記(如 <c:if>)隱藏會發生什麼呢? 第一次顯示組件時,組件被添加到視圖,第二次如果<c:if> 標記不顯示組件, JSF 將從視圖中刪除它。意思就是任何輸入控制項會丟失他們的本地值,你不能再引用這些組件,舉一個例子,看清單3, 它來自清單2的同一頁.
清單 3. 用JSTL標記條件顯示JSF 組件
代碼內容
代碼內容 ... <h:form> <h:outputText value="If you entered a number greater than 10, two input controls will display below."/> <p> <c:if test="${sessionScope.exampleBean.number > 10}"> <h:outputLabel id="inputStringLabel"for="inputString"> <h:outputText id="outputStringLabel" value="Enter in your string. JSF will remember the value unless this control is hidden."/> </h:outputLabel> <h:inputText id="inputString"/> <h:commandButton value="Go!"/> </c:if> </p> </h:form> ... |
如果
exampleBean.number的值比10大, JSTL <c:if> 標記將會執行它的主體。如果主體被執行,那麼所有嵌套其中的組件將增加到視圖並顯示。 如果沒有執行,組件將會刪除 (如果先前已增加). 這顯示在圖1. 如果你用JSTL 條件標記(或其它的定製標記)控制組件的可見度。如果它們沒有顯示,組件將被從視圖中移走。這意思是說組件會忘記他們的本地值。
Figure 1. The JSTL <c:if> tag will execute its body if the value of exampleBean.number is greater than 10. Click on thumbnail to view full-sized image.
圖 2 顯示了清單2和清單3的輸出。頂部輸入欄位(一個 HtmlInputText 組件)的值關聯到了 exampleBean.number的屬性, JSTL <c:forEach>使用它顯示一個字串exampleBean.number次,在頁面底部,如果exampleBean.number的值大於10, JSTL <c:if>標記顯示一個帶有JSF組件的表格。 否由,組件將不會顯示, 並從視圖中移出 (輸入控制項將丟失它的值).
Figure 2. The output of the JSP page shown in Listings 2 and 3. Click on thumbnail to view full-sized image.
你能達到清單3中代碼同樣的效果,通過把組件放入一個 HtmlPanelGroup 並設定它的 rendered 屬性等於同樣的運算式。 HtmlPanelGroup 可以作為多個組件的容器,下面是例子: 代碼內容
代碼內容 <h:panelGroup rendered="#{sessionScope.exampleBean.number > 10}"> <h:outputLabel id="inputStringLabel2" for="inputString"> <h:outputText id="outputStringLabel2" value="Enter in your string. JSF will remember the value."/> </h:outputLabel> <h:inputText id="inputString2"/> <h:commandButton value="Go!"/> </h:panelGroup> |
如果exampleBean.number 大於10,這個面板變得可見。在這種情況下,如果組件沒有顯示也不會刪除。這是一個使用純JSF而不用JSTL的好例子。
Tip: 即使你使用JSTL提供一個有很多功能的定製標記,如果你從零開始開發 (或重做), 你應當首先看看用標準的JSF組件能否實現你想要的行為。使用好的組件和設計良好的backing beans, 在頁面中能消除很多JSTL標記。使用標準的JSF,你能顯示或隱藏面板和做各種各樣的有強大功能的事情。 下面是幾個可以讓JSF標記和JSTL國際化、格式化標記協同工作的條件:
不推薦使用<fmt:parseDate>和<fmt:parseNumber> . 你應該使用一個帶有的日期或數字轉換器的HtmlInputText 組件。
不應該使用<fmt:requestEncoding>標記指定頁面的字元編碼,通常, JSF自動處理。如果你要強迫用特殊的字元編碼, 你應該用JSP頁面指示:
代碼內容 <%page contentType="[contenttype];[charset]"%>. |
也不應該使用<fmt:setLocale> 標記,因為它不知道, 它可能引起你的JSTL標記使用一個地區而你的JSF組件使用另一個, 代替這種災難發生的處方是,你應該使用JSF的國際化特性。為了控制特殊頁面的場所,使用UIViewRoot 組件的locale 屬性。 JSF的國際化特效能在JSF和JSTL兩者中工作。
結合JSF和JSTL能變得十分強大。 在這裡我們示範了你的定製標記或從第三方擷取的標記與JSF、JSTL一起工作。 通常,當可能時,你應該儘可能地使用JSF 標記。