技术开发 频道

在Java EE 6中使用JSF 2.0简化页面制作

  【IT168 文档】过去几个星期,我们对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 
               &nbsp;&nbsp;<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>

  这个Facelets XHTML页面和普通JSP页面并没有多大不同,Facelets支持JSF和JSTL标签库,它也包括一个Facelets标签库,支持功能丰富的页面模板。命名空间声明xmlns:ui="http://java.sun.com/jsf/facelets"就是针对facelets标签库的,但这里没有使用facelets标签库的标签,facelets也支持统一的表达式语言。

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

 

  模板

  使用模板,你可以创建一个页面作为应用程序中其它页面的模板,这样可以避免多次创建结构类似的页面,同时也可以统一应用程序中多个页面的视觉风格。

  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所示。

图 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");
       }
   }  

  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);" />

  代码包括一个标签,它呈现为一个按钮,用户点击这个按钮时,向服务器提交一个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目录。

图 3 JSF应用程序中resources目录下的资源

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

0
相关文章