在Java EE 6中使用JSF 2.0簡化頁面制作
原創【51CTO精選譯文】過去幾個星期,51CTO對Java EE 6的新特性進行了一系列介紹。除了Servlet 3.0的特性,Java EE 6也使用了新的JSF 2.0標準。下面我們來看一看JSF 2.0是如何簡化頁面制作并提供Ajax支持的。***,我們對Servlet 3.0和JSF 2.0的新特性進行了總結。
簡化JSF 2.0頁面制作
JavaServer Faces技術提供了一個服務端組件框架,簡化了Java EE應用程序用戶界面的開發,其中最顯著的改進是頁面制作,通過使用標準的JavaServer Faces視圖聲明語言(JavaServer Faces View Declaration Language,俗稱Facelets)創建一個JSF頁面更加容易。
Facelets
Facelets是一個強大的輕量級聲明語言,可以使用它展示一個JSF頁面,使用Facelets時,你可以使用HTML風格的模板展示一個JSF頁面,也可以構建一個組件樹,JSF應用程序中的用戶界面通常是由JSF組件構成的JSF頁面,Facelets在JSP之上提供了更多優點。
在JSP中,Web頁面中的元素是按照漸進順序處理和渲染的,而JSF提供了它自己的處理和渲染順序,這可能會導致不可預測的行為發生,Facelets解決了這個問題,通過模板,Facelets也允許代碼復用,可以大大減少開發UI的時間,現在Facelets已經成為構建JSF應用程序的***技術。
Facelets通常是使用XHTML標記語言編寫的,因此Facelets是可以跨不同開發平臺的,下面是Java EE 6教材中提供的JSF頁面的Facelets 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" xml:lang="en" lang="en"
- xmlns:f="http://java.sun.com/jsf/core"
- xmlns:h="http://java.sun.com/jsf/html"
- xmlns:ui="http://java.sun.com/jsf/facelets">
- <head>
- <title>Guess Number JSF Application</title>
- </head>
- <body>
- <h:form>
- <h2>
- Hi. My name is Duke. I am thinking of a number from <b>
- <h:outputText value="#{UserNumberBean.minimum}"/> to
- <b>
- <h:outputText value="#{UserNumberBean.maximum}"/>.
- <p>
- Can you guess it ?
- </p>
- <h:graphicImage id="waveImg" url="/wave.med.gif" />
- <h:inputText id="userNo"
- value="#{UserNumberBean.userNumber}">
- converterMessage="#{ErrMsg.userNoConvert}">
- <f:validateLongRange
- minimum="#{UserNumberBean.minimum}"
- maximum="#{UserNumberBean.maximum}"/>
- </h:inputText>
- <h:commandButton id="submit"
- action="success" value="submit" />
- <h:message showSummary="true" showDetail="false"
- style="color: red;
- font-family: 'New Century Schoolbook', serif;
- font-style: oblique;
- text-decoration: overline"
- id="errors1"
- for="userNo"/>
- </h2>
- </h:form>
- </body>
- </html>
頁面渲染效果如圖1所示。
這個Facelets XHTML頁面和普通JSP頁面并沒有多大不同,Facelets支持JSF和JSTL標簽庫,它也包括一個Facelets標簽庫,支持功能豐富的頁面模板。命名空間聲明xmlns:ui="http://java.sun.com/jsf/facelets"就是針對facelets標簽庫的,但這里沒有使用facelets標簽庫的標簽,facelets也支持統一的表達式語言。
模板
使用模板,你可以創建一個頁面作為應用程序中其它頁面的模板,這樣可以避免多次創建結構類似的頁面,同時也可以統一應用程序中多個頁面的視覺風格。
Facelets標簽庫包括一個模板標簽<ui:insert>,為了實施模板化,首先創建一個包括<ui:insert>標簽的模板頁面,然后創建一個使用這個模板的客戶端頁面,在客戶端頁面中,使用<ui:composition>標簽指定模板,使用<ui:define>標簽指定插入到模板中的內容。
下面是一個模板頁面的內容:
- <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:ui="http://java.sun.com/jsf/facelets"
- xmlns:h="http://java.sun.com/jsf/html"
- <head>
- <title><ui:insert name="title">Page Title</ui:insert</title><body>
- </head>
- <body>
- <div>
- <ui:insert name="Links"/>
- </div>
- <div>
- <ui:insert name="Data"/>
- </div>
- </body>
- </html>
下面是使用這個模板的客戶端頁面代碼:
- <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:ui="http://java.sun.com/jsf/facelets"
- xmlns:h="http://java.sun.com/jsf/html"
- <body>
- <ui:composition template="/template.xhtml">
- This text will not be displayed.
- <ui:define name="title">
- Welcome page
- </ui:define>
- <ui:define name="Links">
- ... [Links should be here]
- </ui:define>
- <ui:define name="Links">
- ... [Data should be here]
- </ui:define>
- </ui:composition>
- This text also will not be displayed.
- </body>
- </html>
當客戶端調用這個模板時,它使用標題Welcome Page渲染這個頁面,這個頁面顯示了兩部分內容,一個顯示客戶端中指定的鏈接列表,另一個顯示客戶端中指定的數據。
混合組件
混合組件時JSF中的一個新特性,通過它創建自定義JSF組件會更加容易。你可以使用JSF頁面標記和其它JSF組件創建混合組件。在Facelets的標注下,任何XHTML頁面都可以變成一個混合組件。此外,混合組件可以有驗證器,轉換器和監聽器。
創建好混合組件后,你可以將它保存到庫中,以后有需要時就可以調用了。
讓我們創建一個渲染為登錄面板的混合組件,用戶登錄時,組件反饋一個登錄事件,如圖2所示。
下面是混合組件的源代碼:
- <!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:h="http://java.sun.com/jsf/html"
- xmlns:f="http://java.sun.com/jsf/core">
- xmlns:f="http://java.sun.com/jsf/facelets">
- xmlns:composite="http://java.sun.com/jsf/composite">
- <h:head>
- <title>This content will not be displayed in the rendered output</title>
- </h:head>
- <h:body>
- <composite:interface>
- <composite:actionSource name="loginEvent"/>
- </composite:interface>
- <composite:implementation>
- <table>
- <tr>
- <td>Username: <h:inputText id="username" /> </td>
- </tr>
- <tr>
- <td>Password: <h:inputSecret id="password" /></td>
- </tr>
- <tr>
- <td><h:commandButton value="Login" id="loginEvent" /></td>
- </tr>
- </table>
- </composite:implementation>
- </h:body>
- </html>
xmlns:composite="http://java.sun.com/jsf/composite"聲明了混合UI組件的命名空間,<composite:interface>標簽聲明混合組件的使用契約,<composite:attribute>標簽在使用契約中指定<composite:actionSource>標簽,這個表示組件可以暴露一個事件,讓使用這個混合組件的頁面可以輕松訪問它。
<composite:implementation>標簽定義了混合組件的實現,這里的實現是一個簡單的表,它包括用戶名、密碼和登錄按鈕JSF組件。
為了讓混合組件可用,將代碼保存為XHTML文件,將文件放到應用程序根目錄下resources目錄的子目錄中即可。子目錄的名字可以采用包含混合組件的資源庫名字,JSF運行時通過向混合組件的標簽名后追加.xhtml后綴查找混合組件。例如,如果你將標簽命名為loginPanel,那么保存為混合組件的文件名就是loginPanel.xhtml。然后你就可以在Web頁面中使用混合組件了,下面就是一個使用混合組件的Web頁面代碼示例:
- <!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:h="http://java.sun.com/jsf/html"
- xmlns:f="http://java.sun.com/jsf/core"
- xmlns:ui="http://java.sun.com/jsf/facelets"
- xmlns:ez="http://java.sun.com/jsf/composite/ezcomp">
- <head>
- <title>Example 01>/title>
- <style type="text/css">
- .grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9; }
- </style>
- </h:head>
- <h:body>
- <p>Usage of Login Panel Component</p>
- <ui:debug hotkey="p" rendered="true"/>
- <h:form>
- <div id="compositeComponent" class="grayBox" style="border: 1px solid #090;">
- <ez:loginPanel>
- <f:actionListener for="loginEvent" type="example01.LoginActionListener" />
- </ez:loginPanel>
- </div>
- <p><h:commandButton value="reload" /></p>
- <p><h:outputText value="#{loginActionMessage}" /></p>
- </h:form>
- </h:body>
- </html>
注意聲明xmlns:ez="http://java.sun.com/jsf/composite/ezcomp",它指定了混合組件的命名空間和前綴,這里的ezcomp是資源目錄的子目錄名,JSF使用下面的約定:所有命名空間URI都以http://java.sun.com/jsf/composite/開頭,使用資源庫的名稱結束。
<f:actionListener>
標簽關聯混合組件的行為監聽器,標簽中的for屬性表示這個監聽器是為混合組件上名為loginEvent行為事件準備的,你需要編寫代碼來處理事件,例如:
- import javax.faces.component.UIComponent;
- import javax.faces.component.ValueHolder;
- import javax.faces.context.FacesContext;
- import javax.faces.event.AbortProcessingException;
- import javax.faces.event.ActionEvent;
- import javax.faces.event.ActionListener;
- public class LoginActionListener implements ActionListener {
- public void processAction(ActionEvent event) throws AbortProcessingException {
- FacesContext context = FacesContext.getCurrentInstance();
- context.getExternalContext().getRequestMap().put("loginActionMessage",
- "Login event happened");
- }
- }
#p#
JSF 2.0對Ajax的支持
JSF 2.0天生就支持Ajax,利用Ajax技術,Web應用程序在后臺以異步的方式從服務器獲取數據。支持Ajax后,允許頁面局部刷新,允許選擇視圖中的一個組件進行處理而不影響其它組件。
要在JSF中使用Ajax,需要訪問有資源標識符的JavaScript資源jsf.js,它存在于javax.faces資源庫中,包含讓JSF與Ajax交互的JavaScript API,JavaScript API由一組標準的JavaScript函數組成,使JavaServer Faces框架中的Ajax操作變得簡單了,你幾乎不用直接包括這個文件,當你使用任何開啟Ajax的標簽或組件時,JSF會自動包括它。然后你就可以使用<f:ajax>標簽或調用JavaScript API中的函數了。
下面是一個使用<f:ajax>標簽的示例:
- <h:commandButton id="button1">
- <f:ajax execute="..." render="..."/>
- </h:commandButton>
這里的<f:ajax>標簽是嵌套在<h:commandButton>標簽內的,這樣會結合在execute屬性中指定的Ajax行為和<h:commandButton>標簽呈現的命令按鈕,你也可以指定一個event屬性來識別JavaScript DOM事件,如果你不指定event屬性,JSF使用組件的默認行為,這里的默認行為是onclick,因此JSF結合execute屬性中指定的Ajax請求和呈現按鈕的onclick事件。用戶點擊該按鈕時,JSF提交Ajax請求給服務器。
使用<f:ajax>標簽的一個好處是不用在頁面中指定載入jsf.js,它會自動為你載入,相比之下,如果你調用JavaScript API,首先需要使用<h:outputScript>讓jsf.js對當前視圖可用,例如:
- <f:view contentType="text/html"/>
- <h:head>
- <meta...
- <title...
- </h:head>
- <h:body>
- ...
- <h:outputScript name="jsf.js" library="javax.faces" target="body"/>
- ...
- </h:body>
- ...
然后才可以使用JavaScript API中的函數產生Ajax請求。例如,你使用JavaScript函數jsf.ajax.request向服務器發送一個請求,如下面的代碼:
- <h:commandButton id="button1" value="submit">
- onclick="jsf.ajax.request(this,event);" />
代碼包括一個<h:commandButton>標簽,它呈現為一個按鈕,用戶點擊這個按鈕時,向服務器提交一個Ajax請求。
Servlet 3.0和JSF2.0中的更多新特性
Servlet 3.0中另一個新特性是允許你使用ServletContext類中的方法通過編程在Web應用程序啟動時向其添加Servlet和Servlet過濾器,使用addServlet()方法添加Servlet,使用addFilter()添加Servlet過濾器。結合可插拔式共享框架特性,Web框架可以在無開發人員介入的情況下實現自我配置。
#t#此外Servlet 3.0加入了許多安全特性,除了聲明安全外,Server 3.0通過HttpServletRequest接口提供了編程安全,例如,你可以在應用程序中使用HttpServletRequest的authenticate()方法執行用戶名和密碼的收集,或者使用login()方法指向容器驗證一個非強制請求上下文中的請求調用者。有關Servlet 3.0的更多特性,請參閱JSR 315規范。
JSF 2.0中的一些額外增強與資源如何打包和處理有關,JSF 2.0標準化了打包哪里的資源。所有資源都放在resources目錄或一個子目錄下,資源需要按順序正確地進行渲染,例如CSS文件和JavaScript文件,圖3顯示了Netbeans中的一個JSF項目部分結構及文件,注意其中的resources目錄,CSS和images目錄。
JSF 2.0也包括顯示和處理資源的API,使用javax.faces.application.Resource類顯示一個資源,使用javax.faces.application.ResourceHandler類創建資源的實例。有關JSF 2.0的更多信息,請參閱JSR 314規范。
【51CTO.com譯稿,非經授權請勿轉載。合作站點轉載請注明原文譯者和出處為51CTO.com,且不得修改原文內容。】
原文:Introducing the Java EE 6 Platform 作者:Ed Ort