gembin

          OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

          HBase, Hadoop, ZooKeeper, Cassandra

          Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

          There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

          About Me

           

          聯(lián)合使用 CSS、JavaScript 和 JSF 精心打造 Ajax 應(yīng)用程序,第 1 部分: 增強(qiáng) JSF 頁(yè)面的外觀[zhuan]

          使用 JSF 組件的樣式屬性

          幾乎每個(gè) JSF HTML 組件都有兩個(gè)可選屬性,分別為 stylestyleClass,這兩個(gè)屬性在 HTML 輸出中呈現(xiàn)為 styleclass 屬性。一些組件,比如 <h:dataTable><h:panelGrid>,還有針對(duì)于其 facet 的額外樣式屬性。本節(jié)討論與 CSS 相關(guān)的 JSF HTML 庫(kù)屬性。

          將 CSS 文件鏈接到 JSF 頁(yè)面

          如果 Web 頁(yè)面具有獨(dú)特的樣式,可以在頁(yè)面頁(yè)眉的 <style> 元素內(nèi)定義樣式規(guī)則。也可以使用 style 屬性為單個(gè) JSF 組件指定樣式信息。但在大多數(shù)情況下,您可能更愿意在單獨(dú)的 CSS 文件中包含樣式規(guī)則,以便可以將這些樣式規(guī)則應(yīng)用到多個(gè)頁(yè)面。可以使用 <link> 標(biāo)記將外部樣式表鏈接到一個(gè) Web 頁(yè)面,如清單 1 所示:


          清單 1. 使用 <link> 標(biāo)記
                          
          <link rel="stylesheet" type="text/css"
          href="${pageContext.request.contextPath}/MyStyles.css">
          <link rel="stylesheet" type="text/css"
          href="<%=request.getContextPath()%>/styles/MoreStyles.css">


          使用 MyFaces Tomahawk
          如果更愿意使用 JSF 組件,而非 HTML 標(biāo)記,則可以使用 MyFaces Tomahawk 的 <t:stylesheet> 組件,該組件可以呈現(xiàn) <link> 標(biāo)記。

          在清單 1 中,href 屬性包含絕對(duì) URI。也可以為 CSS 文件使用相對(duì)鏈接,但如果 JSF 頁(yè)面包含 /faces/ 前綴,最好是在上下文路徑中包含 ${pageContext.request.contextPath}<%=request.getContextPath()%>。在這種情況下,任何鏈到 CSS 文件、圖像或其他資源的相對(duì)鏈接都將導(dǎo)致一個(gè)包含 /faces/ 前綴的 HTTP 請(qǐng)求,這意味著非 JSF 文件將由 Faces servlet 處理。這雖然可以工作,但效率并不高。若使用 .faces 后綴請(qǐng)求 JSF 頁(yè)面,則盡可以放心地在基于 JSF 的應(yīng)用程序中使用相對(duì)鏈接,因?yàn)檫@樣可以消除上述問(wèn)題。

          定義和使用樣式規(guī)則

          CSS 文件包含一些樣式表規(guī)則,這些規(guī)則可以應(yīng)用于 JSF 組件能夠呈現(xiàn)的 HTML 元素,也可以被簡(jiǎn)單地包含在 JSF 頁(yè)面的組件之間。比如,如果希望只有將鼠標(biāo)放到鏈接上時(shí)才出現(xiàn)下劃線,則可以使用如下規(guī)則(參見(jiàn)清單 2):


          清單 2. 鏈接的樣式規(guī)則
                          
          a { text-decoration: none; }
          a:hover { text-decoration: underline; }

          這些規(guī)則可應(yīng)用于任何鏈接,無(wú)論 <a> 元素是直接包含在 JSF 頁(yè)面還是由諸如 <h:commandLink> 這樣的 JSF 組件生成(參見(jiàn)清單 3):


          清單 3. HTML 和 JSF 鏈接
                          
          <a href="LinkStyles.faces">HTML Link</a>
          <h:commandLink value="JSF Link"/>

          清單 4 給出了如何為 JSF 組件指定內(nèi)聯(lián)樣式。


          清單 4. 具有樣式屬性的 JSF 組件
                          
          <h:commandLink value="Red Link" style="color: red"/>

          然而在大多數(shù)情況下,都是在 CSS 文件中定義樣式類(參見(jiàn)清單 5),以便可以將相同的樣式規(guī)則應(yīng)用于多個(gè)組件。


          清單 5. 樣式類示例
                          
          .GreenClass { color: green; }

          此樣式類的名稱將會(huì)通過(guò) styleClass 屬性提供給 JSF 組件,如清單 6 所示。


          清單 6. 具有 styleClass 屬性的 JSF 組件
                          
          <h:commandLink value="Green Link" styleClass="GreenClass"/>

          清單 1-6 的代碼可以從本文的示例代碼鏈接給出的 LinkStyles.jspLinkStyles.css 文件中找到(參見(jiàn) 下載)。

          具有多個(gè)樣式類的 JSF 組件

          正如之前所提到的,一些 JSF 組件具有多個(gè)樣式屬性。例如,<h:message><h:messages> 就有如下所示的 10 個(gè)與 CSS 相關(guān)的屬性:

          • style
          • styleClass
          • errorClass
          • errorStyle
          • fatalClass
          • fatalStyle
          • infoClass
          • infoStyle
          • warnClass
          • warnStyle

          根據(jù)所呈現(xiàn)的消息的嚴(yán)重程度,只有兩個(gè)屬性會(huì)應(yīng)用到每個(gè)消息。UISelectOneUISelectMany 組件的 JSF 標(biāo)記接受所呈現(xiàn)的列表項(xiàng)的 enabledClassdisabledClass 屬性。<h:dataTable><h:panelGrid> 標(biāo)記 則有針對(duì)主表、頁(yè)眉、頁(yè)腳、行和列的類屬性。下面的示例展示了如何使用與 CSS 相關(guān)的數(shù)據(jù)表屬性,這個(gè)數(shù)據(jù)表在下面的屏幕截圖中給出。


          圖 1. TableStyles 示例
          Tablestyles 示例

          首先,需要為這個(gè)表組件建立數(shù)據(jù)模型。OrderBean 類(如清單 7 所示)擴(kuò)展了 javax.faces.model.ArrayDataModel。實(shí)際的應(yīng)用程序會(huì)從數(shù)據(jù)庫(kù)中獲得模型的數(shù)據(jù),但為了簡(jiǎn)便起見(jiàn),OrderBean 將由一個(gè)靜態(tài)數(shù)組初始化。


          清單 7. OrderBean 示例
                          
          package jsfcssjs;

          import javax.faces.model.ArrayDataModel;

          public class OrderBean extends ArrayDataModel {
          private static ItemBean items[] = new ItemBean[] {
          new ItemBean("Domain Name", 3, 7.99f),
          new ItemBean("SSL Certificate", 1, 119.00f),
          new ItemBean("Web Hosting", 1, 19.95f),
          new ItemBean("Email Box", 20, 0.15f),
          new ItemBean("E-Commerce Setup", 1, 25.00f),
          new ItemBean("Technical Support", 1, 50.00f)
          };

          public OrderBean(){
          super(items);
          }

          public float getTotalPrice(){
          float total = 0;
          for (int i = 0; i < items.length; i++)
          total += items[i].getItemPrice();
          return total;
          }

          }

          ItemBean 類(參見(jiàn)清單 8)具有三個(gè)讀/寫屬性(descriptionquantityunitPrice)和一個(gè)只讀屬性(itemPrice)。


          清單 8. ItemBean 示例
                          
          package jsfcssjs;

          public class ItemBean implements java.io.Serializable {
          private String description;
          private int quantity;
          private float unitPrice;

          public ItemBean(){
          }

          public ItemBean(String description, int quantity, float unitPrice){
          this.description = description;
          this.quantity = quantity;
          this.unitPrice = unitPrice;
          }

          ...

          public float getItemPrice(){
          return unitPrice * quantity;
          }

          }

          TableStyles.css 文件(如清單 9 所示)包含用于此數(shù)據(jù)表的樣式。


          清單 9. TableStyles.css 示例
                          
          body { font-family: Arial; }
          .tablebg { background-color: #D0D0A0; }
          .header { font-weight: bold; }
          .footer { font-weight: bold; }
          .text { text-align: left; }
          .number { text-align: right; }
          .graybg { background-color: #DDDDDD; }
          .whitebg { background-color: #FFFFFF; }

          TableStyles.jsp 示例(參見(jiàn)清單 10)包含一個(gè) JSF 表組件,該組件使用在 TableStyles.css 中定義的樣式類。styleClass 屬性的值用于 <table> 元素。headerClassfooterClass 屬性為此表的頁(yè)眉和頁(yè)腳單元格指定樣式。columnClasses 屬性包含用于數(shù)據(jù)單元格的 <td> 元素的類的列表(用逗號(hào)分隔)。

          另外一個(gè)類的列表通過(guò) rowClasses 屬性指定。這些類用于此表的 <tr> 元素。在 TableStyles.jsp 示例中,只有兩個(gè)行類,但此表卻有 6 行。<h:dataTable> 組件的 JSF 呈現(xiàn)器會(huì)交替使用這兩個(gè)樣式類,為第一、三和五行使用 graybg 類,為第二、四和六行使用 whitebg 類。var 屬性定義一個(gè)變量,稱為 row,可用來(lái)在呈現(xiàn)期間訪問(wèn)當(dāng)前行的數(shù)據(jù)。全部數(shù)據(jù)從 orderBean 模型獲得,該模型通過(guò) value 屬性綁定到此表。


          清單 10. TableStyles.jsp 示例
                          
          <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
          <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

          <f:view>
          <html>
          <head>
          <title>Order Table</title>
          <link rel="stylesheet" type="text/css"
          href="<%=request.getContextPath()%>/styles/TableStyles.css">
          </head>
          <body>
          <h1>Order Table</h1>
          <h:dataTable id="table" var="row" value="#{orderBean}"
          styleClass="tablebg" headerClass="header" footerClass="footer"
          columnClasses="text,number,number,number"
          rowClasses="graybg,whitebg" border="0" cellpadding="5">
          <h:column>
          <f:facet name="header">
          <h:outputText value="Description"/>
          </f:facet>
          <h:outputText value="#{row.description}"/>
          <f:facet name="footer">
          <h:outputText value="Total Price"/>
          </f:facet>
          </h:column>
          <h:column>
          <f:facet name="header">
          <h:outputText value="Quantity"/>
          </f:facet>
          <h:outputText value="#{row.quantity}"/>
          </h:column>
          <h:column>
          <f:facet name="header">
          <h:outputText value="Unit Price"/>
          </f:facet>
          <h:outputText value="#{row.unitPrice}">
          <f:convertNumber type="currency" currencyCode="USD"
          minFractionDigits="2" maxFractionDigits="2"/>
          </h:outputText>
          </h:column>
          <h:column footerClass="footer number">
          <f:facet name="header">
          <h:outputText value="Item Price"/>
          </f:facet>
          <h:outputText value="#{row.itemPrice}">
          <f:convertNumber type="currency" currencyCode="USD"
          minFractionDigits="2" maxFractionDigits="2"/>
          </h:outputText>
          <f:facet name="footer">
          <h:outputText value="#{orderBean.totalPrice}">
          <f:convertNumber type="currency" currencyCode="USD"
          minFractionDigits="2" maxFractionDigits="2"/>
          </h:outputText>
          </f:facet>
          </h:column>
          </h:dataTable>
          </body>
          </html>
          </f:view>

          清單 11 給出了由 TableStyles.jsp 頁(yè)面生成的 HTML。


          清單 11. 由 TableStyles.jsp 生成的 HTML
                          
          <html>
          <head>
          <title>Order Table</title>
          <link rel="stylesheet" type="text/css"
          href="/jsf12css/styles/TableStyles.css">
          </head>
          <body>
          <h1>Order Table</h1>

          <table id="table" class="tablebg" border="0" cellpadding="5">
          <thead>
          <tr>
          <th class="header" scope="col">Description</th>
          <th class="header" scope="col">Quantity</th>
          <th class="header" scope="col">Unit Price</th>
          <th class="header" scope="col">Item Price</th>
          </tr>
          </thead>
          <tfoot>
          <tr>
          <td class="footer">Total Price</td>
          <td class="footer"></td>
          <td class="footer"></td>
          <td class="footer number">$240.92</td>
          </tr>
          </tfoot>
          <tbody>
          <tr class="graybg">
          <td class="text">Domain Name</td>
          <td class="number">3</td>
          <td class="number">$7.99</td>
          <td class="number">$23.97</td>
          </tr>
          <tr class="whitebg">
          <td class="text">SSL Certificate</td>
          <td class="number">1</td>
          <td class="number">$119.00</td>
          <td class="number">$119.00</td>
          </tr>
          <tr class="graybg">
          ...
          </tr>
          <tr class="whitebg">
          ...
          </tr>
          <tr class="graybg">
          ...
          </tr>
          <tr class="whitebg">
          ...
          </tr>
          </tbody>
          </table>

          </body>
          </html>

          TableStyles.jsp 示例中的 JSF 表的最后一個(gè) <h:column> 組件使用 footerClass 屬性為顯示訂單總額的頁(yè)腳單元格指定兩個(gè)類。footernumber 類將會(huì)用于頁(yè)腳單元格的 <td> 元素。<h:column> 組件的 footerClass 屬性只在 JSF 1.2 中可用。如果使用的是較早的 JSF 版本,則必須包裝能在 <div> 元素內(nèi)呈現(xiàn)總額的 <h:outputText> 組件,以便可以添加 number 類的對(duì)齊效果(參見(jiàn)清單 12)。源代碼的壓縮文件包含針對(duì) JSF 1.1 和 JSF 1.2 的代碼示例。


          清單 12. JSF 1.1 版本的 TableStyles.jsp 示例
                          
          <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
          <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

          <f:view>
          ...
          <h:dataTable ...>
          ...
          <h:column>
          ...
          <f:facet name="footer">
          <h:panelGroup>
          <f:verbatim><div class="number"></f:verbatim>
          <h:outputText value="#{orderBean.totalPrice}">
          <f:convertNumber type="currency" currencyCode="USD"
          minFractionDigits="2" maxFractionDigits="2"/>
          </h:outputText>
          <f:verbatim></div></f:verbatim>
          </h:panelGroup>
          </f:facet>
          </h:column>
          </h:dataTable>
          ...
          </f:view>

          為 JSF 組件設(shè)置默認(rèn)樣式

          在構(gòu)建具有很多 JSF 頁(yè)面的大型應(yīng)用程序時(shí),您可能不喜歡手動(dòng)設(shè)置每個(gè)組件實(shí)例的 styleClass 屬性。標(biāo)準(zhǔn)的 JSF HTML 組件沒(méi)有默認(rèn)樣式,但是您將在本節(jié)中看到,可以遍歷此 JSF 組件樹(shù)并程序化地設(shè)置默認(rèn)的樣式類。要實(shí)現(xiàn)此操作,需要知道這些樹(shù)是如何創(chuàng)建的以及此 HTML 是如何生成的。

          理解 JSF 組件樹(shù)如何構(gòu)建

          所有的 face 請(qǐng)求均由 Faces Servlet 截獲,這是在每個(gè)基于 JSF 的 Web 應(yīng)用程序的 web.xml 描述符中配置的。對(duì)于每個(gè)請(qǐng)求,F(xiàn)aces Servlet 都會(huì)初始化 javax.faces.context.FacesContext 對(duì)象并調(diào)用 javax.faces.lifecycle.Lifecycle 實(shí)例的 execute()render() 方法。execute() 方法處理 JSF 請(qǐng)求處理生命周期中除最后一個(gè)階段(Render Response)之外的每個(gè)階段,最后的這個(gè)階段由 render() 方法執(zhí)行。


          狀態(tài)保存方法
          根據(jù) javax.faces.STATE_SAVING_METHOD 上下文參數(shù)的值(可在 web.xml 文件中設(shè)置),組件樹(shù)或者保存于服務(wù)器或者保存于客戶機(jī)。JSF 實(shí)現(xiàn)可以使用 session 范圍在服務(wù)器端保存此組件樹(shù)。此方法很有效,但若用戶單擊了瀏覽器的后退 按鈕返回到已經(jīng)提交的表單,此 JSF 框架就會(huì)陷入困惑。最好是在客戶機(jī)端保存每個(gè)組件樹(shù),客戶機(jī)端的一個(gè)隱藏的表單元素保存與此頁(yè)面實(shí)例相關(guān)的樹(shù)的序列化后的副本。在客戶機(jī)端保存組件樹(shù)會(huì)增 加流量,并且需要額外的 CPU 資源來(lái)對(duì)對(duì)象樹(shù)進(jìn)行序列化和去序列化,但是與使用 session 范圍相比,這種方法更加可靠。

          在第一個(gè)階段(名為 Restore View),JSF 實(shí)現(xiàn)獲取應(yīng)用程序的視圖處理程序,它是一個(gè) javax.faces.application.ViewHandler 實(shí)例,如果請(qǐng)求是一個(gè) post back(比如,用戶單擊了提交按鈕),還會(huì)調(diào)用 restoreView() 方法。在這種情況下,此組件樹(shù)應(yīng)該在處理之前的 Faces 請(qǐng)求期間構(gòu)造和保存(參見(jiàn)側(cè)欄 狀態(tài)保存方法)。

          如果當(dāng)前的請(qǐng)求不是一個(gè) post back(比如,用戶單擊了一個(gè) Faces 鏈接),JSF 實(shí)現(xiàn)調(diào)用當(dāng)前 FacesContextrenderResponse() 方法和 ViewHandler 實(shí)例的 createView() 方法。renderResponse() 調(diào)用會(huì)指導(dǎo) JSF 實(shí)現(xiàn)由當(dāng)前的 Restore View 階段跳到 Render Response 階段。默認(rèn)視圖處理程序的 createView() 方法只創(chuàng)建一個(gè) javax.faces.component.UIViewRoot 組件。此樹(shù)的其余部分將會(huì)在 Render Response 階段創(chuàng)建,在該階段 JSF 實(shí)現(xiàn)調(diào)用視圖處理程序的 renderView() 方法。

          不管是恢復(fù)還是創(chuàng)建組件樹(shù),JSF 實(shí)現(xiàn)都會(huì)在 renderView() 方法執(zhí)行期間的某個(gè)階段將 HTTP 請(qǐng)求轉(zhuǎn)發(fā)給相關(guān)的 JSF 頁(yè)面。比如,如果請(qǐng)求 /MyApp/MyPage.faces/MyApp/faces/MyPage.jsp,那么所執(zhí)行的 JSF 頁(yè)面的 URI 就是 /MyApp/MyPage.jsp

          任何 JSF 頁(yè)面都包含組件標(biāo)記,比如 <f:view><h:form>,這些標(biāo)記都受 JSP 標(biāo)記處理程序支持。這是一些 Java™ 類,它們實(shí)現(xiàn)在 javax.servlet.jsp.tagext 包中定義的接口。當(dāng)執(zhí)行此頁(yè)時(shí),JSP 容器會(huì)創(chuàng)建標(biāo)記處理程序的實(shí)例并調(diào)用它們的方法。JSF 1.2 組件的所有標(biāo)記處理程序都擴(kuò)展了 javax.faces.webapp.UIComponentELTag。如果使用的是 JSF 1.1 API,則此標(biāo)記處理程序類擴(kuò)展 javax.faces.webapp.UIComponentTagjavax.faces.webapp.UIComponentBodyTag。不管使用的是哪個(gè) JSF 版本,如果組件樹(shù)沒(méi)有在 Restore View 階段恢復(fù),JSF 標(biāo)記處理程序?qū)?huì)在 Render Response 階段創(chuàng)建組件實(shí)例。

          您可能會(huì)嘗試通過(guò)實(shí)現(xiàn) javax.faces.event.PhaseListener 來(lái)設(shè)置默認(rèn)的樣式,但當(dāng)用戶以單擊鏈接或在 Web 瀏覽器中輸入 URL 的方式請(qǐng)求頁(yè)面時(shí),這種方法不會(huì)生效。在這種情況下,JSF 實(shí)現(xiàn)不能恢復(fù)組件樹(shù),此樹(shù)必須在 Render Response 階段創(chuàng)建。在最后階段之前,組件樹(shù)并不存在,在呈現(xiàn)了響應(yīng)之后再更新組件樣式就太晚了,因?yàn)?HTML 輸出已經(jīng)生成。因此,默認(rèn)的樣式必須在呈現(xiàn)組件之前的 Render Response 階段執(zhí)行期間設(shè)置。

          在呈現(xiàn)之前遍歷組件樹(shù)

          JSF 組件有一個(gè)有趣的只讀屬性,稱為 rendersChildren。如果該屬性為 false,只有 encodeBegin()encodeEnd() 方法會(huì)被調(diào)用來(lái)呈現(xiàn)此組件。如果 getRendersChildren() 返回 true,那么 encodeChildren() 也會(huì)在 Render Response 階段被調(diào)用。這些方法通常會(huì)將呈現(xiàn)指派給另一個(gè)類,該類必須實(shí)現(xiàn) javax.faces.render.Renderer 接口,但 JSF 組件也可以生成 HTML,無(wú)需使用呈現(xiàn)器。

          當(dāng)使用 JSF 1.1 時(shí),編碼方法最初都由標(biāo)記處理程序方法調(diào)用。但是,如果組件呈現(xiàn)自身的子組件,那么嵌套組件的所有標(biāo)記處理程序都會(huì)停止調(diào)用編碼方法,因?yàn)槌尸F(xiàn)將會(huì)由另一些組件負(fù)責(zé),這些組件的 getRendersChildren() 方法返回 true。這種在 JSF 1.1 中實(shí)現(xiàn)的呈現(xiàn)過(guò)程十分有效,因?yàn)樗鼘⒕彌_降到了最低,但它需要應(yīng)用程序開(kāi)發(fā)人員在 <f:verbatim> 組件中包含 HTML 內(nèi)容。在 JSF 1.2 中,由于呈現(xiàn)只會(huì)在整個(gè)組件樹(shù)創(chuàng)建之后才執(zhí)行,所以不需要使用 <f:verbatim>

          不管使用的是 JSF 1.1 還是 1.2,只要調(diào)用了 encodeChildren(),嵌套組件都會(huì)被完全初始化并準(zhǔn)備好被呈現(xiàn)。因此,此時(shí)就是設(shè)置默認(rèn)樣式的最佳時(shí)機(jī)。接下來(lái),您會(huì)看到如何創(chuàng)建一個(gè)定制組件來(lái)為它的所有嵌套組件設(shè)置 styleClass 屬性,遞歸遍歷 JSF 組件樹(shù)。

          這里所展示的技巧可以用來(lái)設(shè)置 JSF 組件的任何屬性,而不僅僅是默認(rèn)的樣式。因而,最好是創(chuàng)建一個(gè)可重用的通用基類。SetupComponent 類擴(kuò)展 JSF API 的 UIComponentBase 類,并定義一個(gè)名為 setup() 的抽象方法,可以對(duì)支持呈現(xiàn)的每個(gè)嵌套組件調(diào)用該方法。setupTree() 方法(如清單 13 所示)執(zhí)行 JSF 組件樹(shù)的遞歸遍歷。


          清單 13. SetupComponent 類的 setup() 和 setupTree() 方法
                          
          package jsfcssjs;

          import javax.faces.component.UIComponent;
          import javax.faces.component.UIComponentBase;
          import javax.faces.context.FacesContext;
          ...
          public abstract class SetupComponent extends UIComponentBase {

          protected abstract void setup(FacesContext ctx, UIComponent comp);

          protected void setupTree(FacesContext ctx, UIComponent comp){
          if (!comp.isRendered())
          return;
          setup(ctx, comp);
          for (UIComponent child : comp.getChildren())
          setupTree(ctx, child);
          }
          ...
          }

          繼承自 UIComponentBasegetRendersChildren() 方法(參見(jiàn)清單 14)被覆蓋以返回 true,以便設(shè)置組件能夠控制其子組件的呈現(xiàn)。


          清單 14. SetupComponent 類的 getRendersChildren()方法
                          
          public abstract class SetupComponent extends UIComponentBase {
          ...
          public boolean getRendersChildren(){
          return true;
          }
          ...
          }

          清單 15 中所示的 encodeChildren() 方法被覆蓋,以便在為每個(gè)子組件調(diào)用 encodeTree() 之前調(diào)用 setupTree()


          清單 15. SetupComponent 類的 encodeChildren() 方法
                          
          public abstract class SetupComponent extends UIComponentBase {
          ...
          public void encodeChildren(FacesContext ctx)
          throws IOException {
          if (!isRendered())
          return;
          setupTree(ctx, this);
          for (UIComponent child : getChildren())
          encodeTree(ctx, child);
          }
          ...
          }

          encodeTree() 方法(參見(jiàn)清單 16)為當(dāng)前組件調(diào)用編碼方法,如果 getRendersChildren()返回 false,則還會(huì)為子組件遞歸調(diào)用此方法。


          清單 16. SetupComponent 類的 encodeTree() 方法
                          
          public abstract class SetupComponent extends UIComponentBase {
          ...
          protected void encodeTree(FacesContext ctx, UIComponent comp)
          throws IOException {
          if (!comp.isRendered())
          return;
          comp.encodeBegin(ctx);
          if (comp.getRendersChildren())
          comp.encodeChildren(ctx);
          else
          for (UIComponent child : comp.getChildren())
          encodeTree(ctx, child);
          comp.encodeEnd(ctx);
          }

          }

          創(chuàng)建和配置一個(gè)定制組件

          清單 17 中所示的 DefaultStylesComponent 類擴(kuò)展 SetupComponent 并實(shí)現(xiàn) setup() 方法,以設(shè)置 styleClass 屬性,此屬性的值構(gòu)建在組件系列的名稱和呈現(xiàn)器的名稱之上。


          清單 17. DefaultStylesComponent 類
                          
          package jsfcssjs;

          import javax.faces.component.UIComponent;
          import javax.faces.context.FacesContext;

          import java.util.Map;

          public class DefaultStylesComponent extends SetupComponent {

          protected void setup(FacesContext ctx, UIComponent comp){
          Map<String, Object> attrMap = comp.getAttributes();
          if (attrMap.get("styleClass")!= null)
          return;
          String familyName = getLastName(comp.getFamily());
          String rendererName = getLastName(comp.getRendererType());
          if (familyName == null || rendererName == null)
          return;
          String className = "Default" + familyName;
          if (!familyName.equals(rendererName))
          className += rendererName;
          attrMap.put("styleClass", className);
          }

          protected String getLastName(String fullName){
          if (fullName == null)
          return null;
          int dotIndex = fullName.lastIndexOf('.');
          if (dotIndex != -1)
          return fullName.substring(dotIndex+1);
          else
          return fullName;
          }

          public String getFamily(){
          return "DefaultStyles";
          }

          }

          DefaultStylesComponentfaces-config.xml 中配置,如清單 18 所示。


          清單 18. 在 faces-config.xml 中配置 DefaultStylesComponent
                          
          <faces-config ...>
          ...
          <component>
          <component-type>DefaultStylescomponent</component-type>
          <component-class>jsfcssjs.DefaultStylesComponent</component-class>
          <component-extension>
          <component-family>DefaultStyles</component-family>
          </component-extension>
          </component>

          </faces-config>

          實(shí)現(xiàn)定制標(biāo)記

          DefaultStylesTag 類(參見(jiàn)清單 19)擴(kuò)展由 JSF 1.2 API 定義的 UIComponentELTag 類,并實(shí)現(xiàn) getComponentType()getRendererType() 方法以分別返回 DefaultStylesComponentnull。如果使用的是 JSF 1.1,標(biāo)記類必須擴(kuò)展 UIComponentTag,而非 UIComponentELTag


          清單 19. DefaultStylesTag 類
                          
          package jsfcssjs;

          import javax.faces.webapp.UIComponentELTag;

          public class DefaultStylesTag extends UIComponentELTag {

          public String getComponentType(){
          return "DefaultStylesComponent";
          }

          public String getRendererType(){
          return null;
          }

          }

          css.tld 文件(如清單 20 所示)定義了定制標(biāo)記的 defaultStyles 名稱和屬性。對(duì) idbindingrendered 屬性的支持均繼承自 UIComponentELTag


          清單 20. 用于 JSF 1.2 和 JSP 2.1 的 css.tld 文件
                          
          <?xml version="1.0" encoding="UTF-8" ?>
          <taglib xmlns="http://java.sun.com/xml/ns/javaee" ... version="2.1">
          <tlib-version>1.0</tlib-version>
          <short-name>css</short-name>
          <uri>/css.tld</uri>
          <tag>
          <name>defaultStyles</name>
          <tag-class>jsfcssjs.DefaultStylesTag</tag-class>
          <body-content>JSP</body-content>
          <attribute>
          <name>id</name>
          <required>false</required>
          <rtexprvalue>true</rtexprvalue>
          </attribute>
          <attribute>
          <name>binding</name>
          <required>false</required>
          <deferred-value>
          <type>jsfcssjs.DefaultStylesComponent</type>
          </deferred-value>
          </attribute>
          <attribute>
          <name>rendered</name>
          <required>false</required>
          <deferred-value>
          <type>boolean</type>
          </deferred-value>
          </attribute>
          </tag>
          </taglib>

          如果使用的是 JSF 1.1,TLD 文件應(yīng)該遵從 JSP 1.2 規(guī)范定義的語(yǔ)法(參見(jiàn)清單 21)。


          清單 21. 用于 JSF 1.1 和 JSP 1.2 的 css.tld 文件
                          
          <?xml version="1.0" encoding="UTF-8" ?>
          <!DOCTYPE taglib
          PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
          "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
          <taglib>
          <tlib-version>1.0</tlib-version>
          <jsp-version>1.2</jsp-version>
          <short-name>css</short-name>
          <uri>/css.tld</uri>
          <tag>
          <name>defaultStyles</name>
          <tag-class>jsfcssjs.DefaultStylesTag</tag-class>
          <body-content>JSP</body-content>
          <attribute>
          <name>id</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>binding</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          <attribute>
          <name>rendered</name>
          <required>false</required>
          <rtexprvalue>false</rtexprvalue>
          </attribute>
          </tag>
          </taglib>

          在 JSF 頁(yè)使用定制組件


          developerWorks Ajax 資源中心
          訪問(wèn) Ajax 資源中心,這是一個(gè)一站式中心,其中包含開(kāi)發(fā) Ajax 應(yīng)用程序所需的免費(fèi)工具、代碼和信息。活躍 Ajax 社區(qū)論壇 可能有針對(duì)您的問(wèn)題的答案,該論壇由 Ajax 專家 Jack Herrington 主持。

          本節(jié)中給出的 JSF 示例展示了如何使用背景顏色和邊框來(lái)增強(qiáng) JSF 組件的外觀。


          圖 2. DefaultStyles 示例
          defaultstyles 示例

          清單 22 展示的是 DefaultStyles.css 文件,該文件定義了幾個(gè)用于 DefaultStyles.jsp 示例的樣式類。


          清單 22. DefaultStyles.css 示例
                          
          .DefaultForm {}
          .DefaultPanelGrid { background-color: #FFFFFF; }
          .DefaultInputText { background-color: #FFDDDD;
          border-style: ridge; border-width: thin; }
          .DefaultInputTextarea { background-color: #DDFFDD;
          border-style: groove; border-width: thick; }
          .DefaultSelectOneMenu { background-color: #DDDDFF;
          border-style: inset; border-width: medium; }
          .DefaultCommandButton { background-color: #DDDDDD;
          border-style: outset; border-width: medium; }
          .SpecialInputText { background-color: #DDFFFF;
          border-style: double; border-width: thick; }
          .EnabledOption { color: #FF0000; }
          .DisabledOption { color: #0000FF; }

          DefaultStyles.jsp 示例 (參見(jiàn)清單 23)使用了 <css:defaultStyles> 組件為不具有 styleClass 屬性的 JSF 組件設(shè)置默認(rèn)樣式。其中的一個(gè)組件使用 SpecialInputText 樣式類。EnabledOptionDisabledOption 類用于下拉列表項(xiàng)。


          清單 23. DefaultStyles.jsp 示例
                          
          <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
          <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
          <%@ taglib prefix="css" uri="/css.tld" %>

          <f:view>
          <html>
          <head>
          <title>Default Styles</title>
          <link rel="stylesheet" type="text/css"
          href="<%=request.getContextPath()%>/styles/DefaultStyles.css">
          </head>
          <body>
          <h1>Default Styles</h1>
          <css:defaultStyles>
          <h:form id="form">
          <h:panelGrid columns="1" border="0" cellspacing="5">
          <h:inputText id="text" size="30" value="default text style"/>
          <h:inputText id="special" size="30" value="special text style"
          styleClass="SpecialInputText"/>
          <h:selectOneMenu id="menu" enabledClass="EnabledOption"
          disabledClass="DisabledOption">
          <f:selectItem itemValue="First" itemLabel="First"/>
          <f:selectItem itemValue="Second" itemLabel="Second"/>
          <f:selectItem itemValue="Third" itemLabel="Third"
          itemDisabled="true"/>
          </h:selectOneMenu>
          <h:inputTextarea id="area" rows="5" cols="30"
          value="default text area style"/>
          <h:commandButton id="button" value="Submit"/>
          </h:panelGrid>
          </h:form>
          </css:defaultStyles>
          </body>
          </html>
          </f:view>

          清單 24 給出了由 DefaultStyles.jsp 頁(yè)面產(chǎn)生的 HTML。您將注意到所有的表單元素都有一個(gè) class 屬性。以 Default 開(kāi)始的那些類名均由 <css:defaultStyles> 組件設(shè)置。


          分享本篇文章……

          digg 提交到 Digg
          del.icio.us 發(fā)布到 del.icio.us

          清單 24. DefaultStyles.jsp 產(chǎn)生的 HTML
                          
          <html>
          <head>
          <title>Default Styles</title>
          <link rel="stylesheet" type="text/css"
          href="/jsf12css/styles/DefaultStyles.css">
          </head>
          <body>
          <h1>Default Styles</h1>

          <form id="form" ... class="DefaultForm" ...>
          <input type="hidden" name="form" value="form" />
          <table class="DefaultPanelGrid" border="0" cellspacing="5">
          <tbody>
          <tr>
          <td><input id="form:text" type="text" ...
          class="DefaultInputText" .../></td>
          </tr>
          <tr>
          <td><input id="form:special" type="text" ...
          class="SpecialInputText" .../></td>
          </tr>
          <tr>
          <td><select id="form:menu" ... class="DefaultSelectOneMenu" ...>
          <option value="First" class="EnabledOption">First</option>
          <option value="Second" class="EnabledOption">Second</option>
          <option value="Third" disabled="disabled"
          class="DisabledOption">Third</option>
          </select></td>
          </tr>
          <tr>
          <td><textarea id="form:area" ...
          class="DefaultInputTextarea" ...> ... </textarea></td>
          </tr>
          <tr>
          <td><input id="form:button" type="submit" ...
          class="DefaultCommandButton" /></td>
          </tr>
          </tbody>
          </table>
          <input type="hidden" ... id="javax.faces.ViewState" value="..." />
          </form>

          </body>
          </html>

          結(jié)束語(yǔ)

          本文討論了標(biāo)準(zhǔn) JSF 組件提供的 CSS 支持。簡(jiǎn)單的組件只有兩個(gè)可選屬性,分別為 stylestyleClass。 更復(fù)雜的組件,比如網(wǎng)格和數(shù)據(jù)表,則會(huì)有針對(duì)其 facet 和元素的額外的 CSS 屬性。本系列的這一部分還介紹了 JSF 如何構(gòu)建組件樹(shù),以及如何在組件呈現(xiàn)之前遍歷這些組件樹(shù)以便可以添加特性,比如默認(rèn)樣式。請(qǐng)繼續(xù)留意本系列的第 2 部分,在該部分您將會(huì)獲得可以讓 JSF 表單更加動(dòng)態(tài)的基于 JavaScript 的技巧。






          回頁(yè)首


          下載

          描述名字大小下載方法
          本文的示例應(yīng)用程序 jsfcssjs_part1_src.zip 25KB HTTP
          關(guān)于下載方法的信息


          參考資料

          學(xué)習(xí)

          獲得產(chǎn)品和技術(shù)

          posted on 2008-03-11 12:57 gembin 閱讀(1356) 評(píng)論(0)  編輯  收藏 所屬分類: JSF

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(6)

          隨筆分類(440)

          隨筆檔案(378)

          文章檔案(6)

          新聞檔案(1)

          相冊(cè)

          收藏夾(9)

          Adobe

          Android

          AS3

          Blog-Links

          Build

          Design Pattern

          Eclipse

          Favorite Links

          Flickr

          Game Dev

          HBase

          Identity Management

          IT resources

          JEE

          Language

          OpenID

          OSGi

          SOA

          Version Control

          最新隨筆

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          free counters
          主站蜘蛛池模板: 正镶白旗| 瓮安县| 宁远县| 蚌埠市| 长兴县| 桦甸市| 马龙县| 阳信县| 杂多县| 镇江市| 长兴县| 洛宁县| 西林县| 奉节县| 新龙县| 长白| 家居| 叶城县| 通江县| 炎陵县| 徐汇区| 东海县| 微博| 双江| 赤壁市| 福建省| 出国| 化州市| 宁城县| 昌吉市| 庐江县| 泾阳县| 饶阳县| 应城市| 玛多县| 航空| 兰溪市| 清丰县| 富源县| 尉犁县| 乌苏市|