天天看點

[Java EE 7] JSF Composite 元件

文章來源:[url]http://www.aptusource.org/2014/04/java-ee-7-jsf-composite-components/[/url]

利用 Facelets 和資源處理的特性,JSF 定義了 Composite 元件,它是一個使用 Facelets 标簽檔案定義的元件,元件中可能包含了一組 JSF 元件。将這個定義 Composite 元件的 .xhtml 檔案放到資源目錄中。這樣,你就可以在 JSF 頁面中的任意地方使用這個可重用的元件了。

Composite 元件在“定義頁面”中定義,在“使用頁面”中使用。在定義頁面中使用 <cc:interface> 定義中繼資料(或參數),使用 <cc:implementation> 定義具體實作。cc 的命名空間是 http://xmlns.jcp.org/jsf/composite/ namespace。在未來版本的 JSF 中,可能會放松定義中繼資料的限制,因為中繼資料可以從具體實作中推斷出來。

從 JSF 1.2 開始就可以定義 Composite 元件了,但是在 1.2 中需要更深地了解 JSF 生命周期并且需要編輯多個檔案。JSF 2.0 開始,使用 Composite 隻需要編輯一個 .xhtml 檔案。

我們看看,如果 Facelet 中有下面的代碼片段用于顯示登入表單:

<h:form>
  <h:panelGrid columns="3">
    <h:outputText value="Name:" />
    <h:inputText value="#{user.name}" id="name"/>
    <h:message for="name" style="color: red" />
    <h:outputText value="Password:" />
    <h:inputText value="#{user.password}" 
                     id="password"/>
    <h:message for="password" style="color: red" />
  </h:panelGrid>

  <h:commandButton actionListener="#{userService.register}"
     id="loginButton" 
     action="status" 
     value="submit"/>
</h:form>
           

這段代碼定義了一個有兩行三列的表格,顯示如下:

[img]http://dl2.iteye.com/upload/attachment/0096/0642/7ad062ad-d659-3ada-824b-ca5ef67e526e.png[/img]

表格中的第一列定義了顯示标簽,第二列定義了輸入框,第三列定義了錯誤提示語顯示位置;表格第一行綁定輸入值到 User.name 屬性,第二行綁定輸入值到 User.password 屬性。頁面還有一個送出按鈕,點選後會送出到 UserService bean 的 register 方法。

如果這個登入表單需要在多個頁面中展示,那麼你需要在每個頁面中編寫上面的表單代碼。更好的做法是将表單代碼定義到 Composite 元件中。首選需要将代碼拷貝到 .xhtml 檔案中,再将檔案拷貝到标準資源目錄中。根據約定優于配置原則,這個代碼段已經自動被配置設定了命名空間和标簽名。

假設登入表單代碼拷貝到了 resources/mycomp/login.xhtml 檔案中,這個定義頁面看起來應該是這樣:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html 
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:cc="http://xmlns.jcp.org/jsf/composite"
      xmlns:h="http://xmlns.jcp.org/jsf/html">

 <!-- INTERFACE -->
 <cc:interface>
 </cc:interface>

 <!-- IMPLEMENTATION -->
 <cc:implementation>
   <h:form>
     <h:panelGrid columns="3">
       <h:outputText value="Name:" />
       <h:inputText value="#{user.name}" id="name"/>

     <!-- . . . -->

   </h:form>
</cc:implementation>
</html>
           

在上面的代碼中,cc:interface 用于定義元件的中繼資料,在 cc:interface 中可以定義:頁面屬性、facets、或事件監聽器等。cc:implementation 中包含了元件的内容。

使用定義的 Composite 元件是,命名空間是 http://xmlns.jcp.org/jsf/composite/ 和 mycomp 組合,标記名稱是去掉 .xhtml 字尾之後的檔案名:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:mc="http://xmlns.jcp.org/jsf/composite/mycomp"
  <!-- . . . -->
  <mc:login/>

</html>
           

假如需要在代碼中綁定另外的屬性(替代 #{user.name})并且在不同的頁面需要送出到不同的背景方法(替代 #{userService.register})。那麼在定義頁面的時候可以将這些值傳入:

<!-- INTERFACE -->
<cc:interface>
  <cc:attribute name="name"/>
  <cc:attribute name="password"/>
  <cc:attribute name="actionListener"
      method-signature=
          "void action(javax.faces.event.Event)"
      targets="ccForm:loginButton"/>
</cc:interface>

<!-- IMPLEMENTATION -->
<cc:implementation>
  <h:form id="ccForm">
  <h:panelGrid columns="3">
    <h:outputText value="Name:" />
    <h:inputText value="#{cc.attrs.name}" id="name"/>
    <h:message for="name" style="color: red" />
    <h:outputText value="Password:" />
    <h:inputText value="#{cc.attrs.password}" 
        id="password"/>
    <h:message for="password" style="color: red" />
  </h:panelGrid>

  <h:commandButton id="loginButton"
                   action="status"
                   value="submit"/>
  </h:form>
</cc:implementation>
           

在上面的代碼中,在 cc:interface 中清晰地定義了各個參數。第三個參數使用了 targets 屬性指向 ccForm:loginButton。

在 cc:implementation 中:

[list]

[*] h:form 擁有 id 屬性。這是必須的,這樣才能顯式引用表單中的送出按鈕。

[*] h:inputText 現在使用 #{cc.attrs.xxx} 替換了 #{user.xxx}。#{cc.attrs} 是一個 EL 表達式,用于在元件中通路元件定義的屬性,在這個例子中元件定義了 name 和 password 兩個屬性。

[*] 屬性 actionListener 中定義了事件監聽器。它使用 method-signature 定義了方法簽名。

[*] h:commandButton 擁有 id 屬性,這樣能在 h:form 中很友善的定位到送出按鈕。

[/list]

在使用頁面中,可以使用下面的代碼來傳入 user、password 和 actionListener:

<ez:login
     name="#{user.name}"
     password="#{user.password}"
     actionListener="#{userService.register}"/>
           

現在,使用頁面可以傳入不同的背景 bean 屬性和不同的送出處理方法。

總的來說,Composite 元件帶來了以下好處:

[list]

[*] 遵循不要重複自己原則,讓你的代碼集中在一個檔案中。

[*] 允許開發者在不使用 Java 代碼和 XML 的情況下定義新元件。

[/list]

文章來源:[url]http://www.aptusource.org/2014/04/java-ee-7-jsf-composite-components/[/url]