IT技术及科技前沿

中文IT博客,为IT专业技术人员提供最全面的信息传播和服务

首页 新随笔 订阅 管理
过去几个星期,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代码部分:

  1. <xml version="1.0" encoding="UTF-8"?> 
  2.            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  3.            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  4.    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" 
  5.            xmlns:f="http://java.sun.com/jsf/core" 
  6.            xmlns:h="http://java.sun.com/jsf/html" 
  7.            xmlns:ui="http://java.sun.com/jsf/facelets"> 
  8.    <head> 
  9.            <title>Guess Number JSF Application</title> 
  10.    </head> 
  11.    <body> 
  12.       <h:form> 
  13.        <h2> 
  14.        Hi. My name is Duke. I am thinking of a number from <b> 
  15.               <h:outputText value="#{UserNumberBean.minimum}"/> to  
  16.               &nbsp;&nbsp;<b> 
  17.        <h:outputText value="#{UserNumberBean.maximum}"/>.  
  18.        <p> 
  19.          Can you guess it ?  
  20.        </p> 
  21.        <h:graphicImage id="waveImg" url="/wave.med.gif" /> 
  22.        <h:inputText id="userNo" 
  23.              value="#{UserNumberBean.userNumber}"> 
  24.           converterMessage="#{ErrMsg.userNoConvert}"> 
  25.        <f:validateLongRange 
  26.              minimum="#{UserNumberBean.minimum}" 
  27.              maximum="#{UserNumberBean.maximum}"/> 
  28.        </h:inputText> 
  29.        <h:commandButton id="submit" 
  30.              action="success" value="submit" /> 
  31.        <h:message showSummary="true" showDetail="false" 
  32.                   style="color: red;  
  33.                    font-family: 'New Century Schoolbook', serif;  
  34.                    font-style: oblique;  
  35.                    text-decoration: overline"  
  36.                    id="errors1" 
  37.                    for="userNo"/> 
  38.        </h2> 
  39.       </h:form> 
  40.    </body> 
  41.    </html> 
  42.  

页面渲染效果如图1所示。

使用Facelets创建的用户界面 
图 1 使用Facelets创建的用户界面

这个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>标签指定插入到模板中的内容。

下面是一个模板页面的内容:

  1. <xml version="1.0" encoding="UTF-8"?> 
  2.    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  3.    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  4.  
  5.    <html xmlns="http://www.w3.org/1999/xhtml" 
  6.          xmlns:ui="http://java.sun.com/jsf/facelets" 
  7.          xmlns:h="http://java.sun.com/jsf/html" 
  8.  
  9.       <head> 
  10.          <title><ui:insert name="title">Page Title</ui:insert</title><body> 
  11.       </head> 
  12.       <body> 
  13.           <div> 
  14.               <ui:insert name="Links"/> 
  15.           </div> 
  16.           <div> 
  17.               <ui:insert name="Data"/> 
  18.          </div> 
  19.       </body> 
  20.    </html> 
  21.  

下面是使用这个模板的客户端页面代码:

  1. <xml version="1.0" encoding="UTF-8"?> 
  2.     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  3.  
  4.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  5.  
  6.     <html xmlns="http://www.w3.org/1999/xhtml" 
  7.           xmlns:ui="http://java.sun.com/jsf/facelets" 
  8.           xmlns:h="http://java.sun.com/jsf/html" 
  9.      <body> 
  10.        <ui:composition template="/template.xhtml"> 
  11.            This text will not be displayed.  
  12.            <ui:define name="title"> 
  13.                Welcome page  
  14.            </ui:define> 
  15.            <ui:define name="Links"> 
  16.                ... [Links should be here]  
  17.            </ui:define> 
  18.            <ui:define name="Links"> 
  19.                ... [Data should be here]  
  20.            </ui:define> 
  21.        </ui:composition> 
  22.            This text also will not be displayed.  
  23.      </body> 
  24.     </html> 

当客户端调用这个模板时,它使用标题Welcome Page渲染这个页面,这个页面显示了两部分内容,一个显示客户端中指定的链接列表,另一个显示客户端中指定的数据。

混合组件

混合组件时JSF中的一个新特性,通过它创建自定义JSF组件会更加容易。你可以使用JSF页面标记和其它JSF组件创建混合组件。在Facelets的标注下,任何XHTML页面都可以变成一个混合组件。此外,混合组件可以有验证器,转换器和监听器。

创建好混合组件后,你可以将它保存到库中,以后有需要时就可以调用了。

让我们创建一个渲染为登录面板的混合组件,用户登录时,组件反馈一个登录事件,如图2所示。

登录面板混合组件 
图 2 登录面板混合组件

下面是混合组件的源代码:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  2.    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  3.    <html xmlns="http://www.w3.org/1999/xhtml" 
  4.       xmlns:h="http://java.sun.com/jsf/html" 
  5.       xmlns:f="http://java.sun.com/jsf/core"> 
  6.       xmlns:f="http://java.sun.com/jsf/facelets"> 
  7.       xmlns:composite="http://java.sun.com/jsf/composite"> 
  8.  
  9.    <h:head> 
  10.    <title>This content will not be displayed in the rendered output</title> 
  11.    </h:head> 
  12.  
  13.    <h:body> 
  14.     <composite:interface> 
  15.            <composite:actionSource name="loginEvent"/> 
  16.     </composite:interface> 
  17.     <composite:implementation> 
  18.      <table> 
  19.     <tr> 
  20.        <td>Username:  <h:inputText id="username" /> </td> 
  21.     </tr> 
  22.     <tr> 
  23.        <td>Password: <h:inputSecret id="password" /></td> 
  24.     </tr> 
  25.     <tr> 
  26.        <td><h:commandButton value="Login" id="loginEvent" /></td> 
  27.     </tr> 
  28.      </table> 
  29.     </composite:implementation> 
  30.    </h:body> 
  31.    </html> 
  32.  

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页面代码示例:

  1. <!DOCTYPE html  
  2.    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  3.    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  4.    <html xmlns="http://www.w3.org/1999/xhtml" 
  5.       xmlns:h="http://java.sun.com/jsf/html" 
  6.       xmlns:f="http://java.sun.com/jsf/core" 
  7.       xmlns:ui="http://java.sun.com/jsf/facelets" 
  8.       xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"> 
  9.  
  10.    <head> 
  11.    <title>Example 01>/title> 
  12.    <style type="text/css"> 
  13.    .grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9;  }  
  14.    </style> 
  15.    </h:head> 
  16.  
  17.    <h:body> 
  18.      <p>Usage of Login Panel Component</p> 
  19.  
  20.         <ui:debug hotkey="p" rendered="true"/> 
  21.  
  22.      <h:form> 
  23.          <div id="compositeComponent" class="grayBox" style="border: 1px solid #090;"> 
  24.             <ez:loginPanel> 
  25.                 <f:actionListener for="loginEvent" type="example01.LoginActionListener" /> 
  26.  
  27.             </ez:loginPanel> 
  28.          </div> 
  29.      <p><h:commandButton value="reload" /></p> 
  30.  
  31.      <p><h:outputText value="#{loginActionMessage}" /></p> 
  32.      </h:form> 
  33.  
  34.    </h:body> 
  35.    </html> 
  36.  

注意声明xmlns:ez="http://java.sun.com/jsf/composite/ezcomp",它指定了混合组件的命名空间和前缀,这里的ezcomp是资源目录的子目录名,JSF使用下面的约定:所有命名空间URI都以http://java.sun.com/jsf/composite/开头,使用资源库的名称结束。

<f:actionListener>

标签关联混合组件的行为监听器,标签中的for属性表示这个监听器是为混合组件上名为loginEvent行为事件准备的,你需要编写代码来处理事件,例如:

  1. import javax.faces.component.UIComponent;  
  2.  import javax.faces.component.ValueHolder;  
  3.  import javax.faces.context.FacesContext;  
  4.  import javax.faces.event.AbortProcessingException;  
  5.  import javax.faces.event.ActionEvent;  
  6.  import javax.faces.event.ActionListener;  
  7.  
  8.  public class LoginActionListener implements ActionListener {  
  9.  
  10.      public void processAction(ActionEvent event) throws AbortProcessingException {  
  11.          FacesContext context = FacesContext.getCurrentInstance();  
  12.          context.getExternalContext().getRequestMap().put("loginActionMessage",  
  13.                  "Login event happened");  
  14.      }  
  15.  }  

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>标签的示例:

  1. <h:commandButton id="button1"> 
  2.       <f:ajax execute="..." render="..."/> 
  3.    </h:commandButton> 
  4.  

这里的<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对当前视图可用,例如:

  1. <f:view contentType="text/html"/> 
  2.      <h:head> 
  3.        <meta... 
  4.        <title... 
  5.      </h:head> 
  6.      <h:body> 
  7.        ...  
  8.        <h:outputScript name="jsf.js" library="javax.faces" target="body"/> 
  9.        ...  
  10.      </h:body> 
  11.      ...  
  12.  

然后才可以使用JavaScript API中的函数产生Ajax请求。例如,你使用JavaScript函数jsf.ajax.request向服务器发送一个请求,如下面的代码:

  1. <h:commandButton id="button1" value="submit"> 
  2.    onclick="jsf.ajax.request(this,event);" /> 
  3.  

代码包括一个<h:commandButton>标签,它呈现为一个按钮,用户点击这个按钮时,向服务器提交一个Ajax请求。

Servlet 3.0和JSF2.0中的更多新特性

Servlet 3.0中另一个新特性是允许你使用ServletContext类中的方法通过编程在Web应用程序启动时向其添加Servlet和Servlet过滤器,使用addServlet()方法添加Servlet,使用addFilter()添加Servlet过滤器。结合可插拔式共享框架特性,Web框架可以在无开发人员介入的情况下实现自我配置。

此外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应用程序中resources目录下的资源 
图 3  JSF应用程序中resources目录下的资源

JSF 2.0也包括显示和处理资源的API,使用javax.faces.application.Resource类显示一个资源,使用javax.faces.application.ResourceHandler类创建资源的实例。有关JSF 2.0的更多信息,请参阅JSR 314规范。

posted on 2011-02-13 13:23  孟和2012  阅读(396)  评论(0编辑  收藏  举报