A first look at JavaServer Faces(jsf 2)
一个简单的JSF例子(A simple JavaServer Faces example)
Figures 2a, 2b, and 2c show a very simple JSF application. The application's opening page contains a link that starts the application. That link points to a JSP page that displays a simple form. Because this simple application does not perform validation, you can click the Log In button without filling in the name and password fields, which will transport you to another JSP page that welcomes you to JavaServer Faces.
图2a、2b、2c展示了一个简单的JSF应用。这个应用的入口页面包含一个启动应用的链接。这个链接指向一个显示一个简单表单的JSP页面。由于这个简单的应用不进行验证操作,所以你在表单的姓名和密码域中不用输入任何内容直接点击Log In按钮,你将被引导到另外一个欢迎你使用JSF的JSP页面。
图 2a 一个简单的JSF应用
图 2b JSF登录界面
图 2c欢迎信息
First, let's explore the logistics of implementing this simple application,
and JavaServer Faces applications in general. JSF requires the following jar files in the WEB-INF/lib directory:
首先,我们浏览一下这个简单的应用和通常的JSF应用需要的支持。JSF需要在WEB-INF/lib目录下存放有一下文件:
WEB-INF/lib/commons-beanutils.jar
WEB-INF/lib/commons-collections.jar
WEB-INF/lib/commons-digester.jar
WEB-INF/lib/commons-logging-api.jar
WEB-INF/lib/jsf-api.jar
WEB-INF/lib/jsf-ri.jar
WEB-INF/lib/jstl.jar
WEB-INF/lib/standard.jar
The jar files listed above are all you need for JSF applications. Even though, as we will see shortly, JSF applications typically use JSP tags implemented by the JSF implementation, there are no separate tag library descriptor (TLD) files because that information is contained in the jar files.
JSF应用需要的所有内容就是上面列举的这些jar文件。当然,我们很快会注意到,JSF应用通常会使用JSF实现中实现的JSP 标签,但是并不需要额外的标签库描述符(TLD)因为这些信息也包含在上面的jar文件中。
Here's a listing of the other files that comprise the application shown in Figure 2:
下面是一些我们这个JSF应用需要的其他文件的清单。
WEB-INF/web.xml
WEB-INF/classes/com/sabreware/listeners/SimpleContextListener.java
WEB-INF/classes/com/sabreware/appHandlers/SimpleApplicationHandler.java
/index.html
/index.jsp
示例1 WEB-INF/web.xml
Example 1. WEB-INF/web.xml
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Context Listener creates and sets the application handler -->
<listener>
<listener-class>
com.sabreware.listeners.SimpleServletContextListener
</listener-class>
</listener>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
The deployment descriptor listed above declares four things:
A servlet context listener
A controller servlet
A mapping for the controller servlet
A welcome file
上面的部署描述符声明了四项内容:
1. 一个Servlet环境(Context)监听器
2. 一个控制器Servlet
3. 控制器Servlet的映射
4. 一个欢迎页面
The deployment descriptor listed in Example 1 associates the JSF controller servlet with the URL /faces/*, which causes the servlet container to map all URLs that start with /faces to the JSF controller servlet. JSF uses the controller servlet to control the JSF lifecycle.
部署描述符将/faces/*这样的URL请求和JSF控制器servlet关联起来,这使得servlet容器将把所有以/faces开头的URL请求映射到这个JSF控制器servlet页面。JSF使用这个控制器servlet控制JSF处理流程。
示例2 servlet运行环境监听器
Example 2. WEB-INF/com/sabreware/listeners/SimpleServletContextListener
- package com.sabreware.listeners;
- import javax.servlet.*;
- import javax.faces.*;
- import javax.faces.lifecycle.*;
- import com.sabreware.appHandlers.SimpleApplicationHandler;
- public class SimpleServletContextListener implements ServletContextListener {
- public void contextInitialized(ServletContextEvent e) {
- LifecycleFactory factory = (LifecycleFactory)
- FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
- Lifecycle lifecycle = factory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
- lifecycle.setApplicationHandler(new SimpleApplicationHandler());
- }
- public void contextDestroyed(ServletContextEvent e) {
- // Nothing to do here
- }
- }
Servlet containers create servlet context listeners at application startup and invoke the listener's contextInitialized() method. When the application shuts down, the servlet container invokes the listener's contextDestroyed() method. The servlet context listener listed above creates an application handler and associates it with the JSF lifecycle. Application handlers handle application events and specify a URL that the JSF implementation subsequently forwards to, as illustrated by the application handler created in Example 2 and listed in Example 3.
servlet容器在应用启动时生成servlet运行环境监听器并调用监听器的contextInitialized()方法。当应用终止时servlet容器调用监听器的contextDestroyed()方法。上文中的servlet运行环境监听器生成一个应用句柄并把它和运行流程关联。应用句柄处理应用事件并且声明JSF实现后续将要将请求前转的URL,过程在示例2和示例3中说明。
示例3 SimpleApplicationHandler
Example 3. WEB-INF/com/sabreware/appHandlers/SimpleApplicationHandler
- package com.sabreware.appHandlers;
- import javax.faces.FactoryFinder;
- import javax.faces.context.FacesContext;
- import javax.faces.event.FacesEvent;
- import javax.faces.lifecycle.ApplicationHandler;
- import javax.faces.tree.TreeFactory;
- public class SimpleApplicationHandler implements ApplicationHandler {
- public boolean processEvent(FacesContext context, FacesEvent facesEvent) {
- TreeFactory treeFactory = (TreeFactory)FactoryFinder.
- getFactory(FactoryFinder.TREE_FACTORY);
- context.setResponseTree(
- treeFactory.getTree(context.getServletContext(),
- "/welcome.jsp"));
- return true;
- }
- }
In the JSF lifecycle's Render Response phase, the JSF implementation forwards to a URL. That URL represents a component tree, which is known as the response tree. The application handler listed above sets the response tree to /welcome.jsp, and the JSF implementation subsequently forwards to that URL after the application handler is invoked (in the Invoke Application phase of the JSF lifecycle). Our simple example only generates one application event—a form event generated when the Log In button is activated. JSF applications can generate two types of application events: form events and command events. Command events are generated when you click on a link.
在JSF处理流程中的响应合成阶段,JSF实现将请求前转到一个URL中。这个URL创建一个叫做响应树的组件树。上文的应用句柄将这个响应树赋予/welcome.jsp,在应用句柄被激活(在调用Web应用阶段)以后JSF实现紧接着前转到这个URL。我们的这个简单的应用仅生成一个应用事件——当Log In按钮被按下时触发的表单事件。JSF应用可以生成两种类型的应用事件:表单事件和命令事件。命令事件通过点击链接生成。
The servlet context listener listed in Example 2 and the application handler listed in Example 3 work hand in hand. The context listener creates the application handler, and the application handler specifies a URL that the JSF implementation forwards to when the login form is submitted.
示例2中的servlet运行环境监听器和示例3中的应用句柄协同工作。运行环境监听器生
成应用句柄,而应用句柄声明了当login表单提交时JSF实现所应当前转的URL。
The welcome file, /index.html, is listed in Example 4.
示例4 欢迎文件,/index.html
Example 4. /index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<font size='4'>Welcome to a simple JavaServer Faces Application</font>
<p>
<a href='faces/index.jsp'>Click here to start the application</a>
<body>
</html>
The welcome file listed above creates a link to the first JSP page displayed by the application. All JSF applications must route the first JSP page displayed by the application through the JSF controller servlet. You can either provide an HTML page that contains a link to that JSP page, as illustrated in this example, or you can rely on the user to type the correct URL to start the application. Unfortunately, neither solution is very appealing; hopefully, JSF 1.0 will provide a mechanism to obviate this requirement.
上文的欢迎文件包含一个指向这个JSF应用显示的第一个JSP页面的链接。所有的JSF应都必须通过JSF控制器导向到各自应用所显示的第一个JSP页面。你可以象示例一样提供一个包含指向这个JSP页面的链接的HTML页面,或者让用户直接输入正确的URL地址以便激活应用。不幸的是,它们都不是很方便;希望在JSF 1.0版本中能提供满足这个需求的机制。
The application's initial JSP page is listed in Example 5.
示例 5 应用的初始JSP页面
Example 5. /index.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri="http://java.sun.com/j2ee/html_basic/" prefix="faces" %>
<font size="4">Please enter your name and password</font>
<faces:usefaces>
<faces:form id="simpleForm" formName="simpleForm">
<table>
<tr>
<td>Name:</td>
<td><faces:textentry_input id="name"/></td>
</tr>
<tr>
<td>Password:</td>
<td><faces:textentry_secret id="password"/></td>
</tr>
</table>
<p><faces:command_button id="submit" commandName="Log In"/>
</faces:form>
</faces:usefaces>
</body>
</html>
The preceding JSP page is where most of the action takes place in our simple application. JSF provides JSP tags for all of the standard components that JSF supports. Those tags must be contained within the body of a <faces:usefaces> tag. The JSP page listed above uses the <faces:form> tag, which creates an HTML form, and the <faces:textentry_input> and <faces:textentry_secret> tags, which render an HTML text element and an HTML password element, respectively. The JSP page also uses the <faces:command_button> tag, which renders an HTML Submit button.
前面的这个JSP页面包含了我们这个简单的应用中大多数的动作。JSF提供了所有JSF支持的标准的组件的JSP 标签。这些tags都必须包含在一个<faces:usefaces>标签所标记的块中。上面的页面通过<faces:form>标签生成一个HTML的表单,<faces:texentry_input> 标签和<faces:textentry_secret>标签分别生成一个HTML的文本输入框和密码输入框。同样通过<faces:command_button>标签提供一个HTML的提交按钮。
When the form in the preceding JSP page is submitted, the JSF lifecycle begins, and the application handler subsequently invokes. That handler specifies /welcome.jsp as the response tree, and the JSF implementation subsequently forwards to that JSP page, which is listed in Example 6.
当前面这个JSP页面中的表单被提交时,JSF的处理流程开始了,应用句柄被调用。这个应用句柄声明/welcome.jsp作为响应树,并且JSF实现随之将请求前转到这个JSP页面中,示例 6说明了这个处理过程。
示例6 /welcome.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
Welcome to JavaServer Faces!
</body>
</html>
Now that we've seen how a simple JSF application works, let's extend that application by adding field validation.
现在我们已经看到了一个简单的JSF应用是如何工作的,下面让我们扩展一下加入字段的验证。
用JSF进行验证
JavaServer Faces provides built-in validation and a framework for creating custom validators. Built-in validation is discussed below; custom validation will be discussed in Part 2.
JSF提供了内建的验证和创建定制的验证的框架。我们首先讨论内建的验证,定制的验证将在第二部分讨论。
内建的验证(Built-in validation)
JavaServer Faces provides the following built-in validators:
JSF提供了以下内建的验证器:
DoubleRangeValidator
LengthValidator
LongRangeValidator
RequiredValidator
StringRangeValidator
The preceding list of validators represent class names. Those classes reside in the javax.faces.validator package. The DoubleRangeValidator and LongRangeValidator validate that a request parameter (which is always a string) can convert to either a double or long, respectively, and that those values fall within a specified range. The LengthValidator checks the string length of a request parameter against minimum or maximum values. The RequiredValidator requires a non-null value for a given field. The StringRangeValidator converts a string into either a long or a double and checks that value against specified minimum or maximum values.
前面罗列的是验证器的类名。这些类都在javax.faces.validator包中。DoubleRangeValidator 和LongRangeValidator验证一个请求参数是否可以转换成为一个双精度浮点数或长整数 并且在某个指定的范围内。LengthValidator验证阐述的长度是否在指定的最小和最大值之间。RequiredValidator检验必须提供的字段是否有非空的数值。StringRangeValidator将一个字符串转换为长整数或者双精度浮点数同时验证是否在指定的最小和最大值之间。
图 3 JSF内建的验证器
Figure 3 shows an error message generated by a length validator. The minimum length was specified as three, but the value entered in the corresponding field was only two characters, so a validation error and corresponding error message were generated when the field's corresponding form was submitted.
图3显示了长度验证器生成的错误信息。最短长度声明为3,但是输入的数据的长度为2,所以当该页面提交的时候出现一个验证错误同时生成了错误信息。
Example 7 lists the JSP page shown in Figure 3.
示例 7 图 3中的JSP页面。
示例 7. 使用长度验证器(Use the LengthValidator)
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 Transitional//EN'>
<html>
<head>
<title>A Simple JavaServer Faces Application</title>
</head>
<body>
<%@ taglib uri='http://java.sun.com/j2ee/html_basic/' prefix='faces' %>
<font size='4'>Please enter your name and password</font>
<faces:usefaces>
<faces:form id='simpleForm' formName='simpleForm'>
<table>
<tr>
<td>Name:</td>
<td>
<faces:textentry_input id='name'>
<faces:validator
className='javax.faces.validator.LengthValidator'/>
<faces:attributename=
'javax.faces.validator.LengthValidator.MINIMUM'
value='3'/>
</faces:textentry_input>
</td>
<td>
<faces:validation_message componentId='name'/>
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<faces:textentry_secret id='password'/>
</td>
</tr>
</table>
<p><faces:command_button id='submit' commandName='Log In'/>
</faces:form>
</faces:usefaces>
</body>
</html>
As evidenced by the preceding JSP page, JSF validators are easy to use: simply add a <faces:validator> tag and one or more <faces:attribute> tags to the body of the component you want to validate. Validators store error
messages in the JSF context when validation fails; you can extract those error messages with the <faces:validation_message>, which lets you specify the component to which those messages apply.
就像前面的JSP页面所说明的,JSF的验证器是非常易于使用的:简单的添加一个<faces:validator>标签和一个或几个<faces:attribute>标签到你希望进行验证的组件中。当验证失败的时候,验证器会将错误信息存储于JSF的运行环境中;你可以使用<faces:validation_message>解析这些信息,它是用于标识具体哪个组件将使用这些信息的。
仍有更多(More to come)
JSF represents a new paradigm for developing J2EE applications.With a well-defined request processing lifecycle, event handling, validation, and a rich component hierarchy for developing complex custom components that can write to multiple devices, JSF will greatly facilitate the development of J2EE application Web tiers.
JSF提出了一种新的开发J2EE应用的框架。通过良好定义的请求处理流程、事件处理、验证机制和可以用于多种设备的用于开发复杂的定制组件的丰富的组件库,JSF将极大的推动基于Web的多层的J2EE应用的开发。
In this article, I introduced basic JavaServer Faces concepts, including the JSF lifecycle, using JSF standard components and their corresponding JSP tags, and built-in validation. In Part 2, I will discuss more advanced JSF features, including custom validation, internationalization, using model objects, and implementing custom components.
通过本文,我介绍了基本的JSF概念,包括JSF处理流程、使用JSF标准组件和对应的标签和内建的验证机制。在第二部分中,我将讨论更多的JSF高级特性,包括定制验证、国际化支持、使用模型对象和实现定制组件。
About the author
David Geary is the author of Core JSTL Mastering the JSP Standard Tag Library (Prentice Hall, 2002; ISBN: 0131001531); Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041); and the Graphic Java series (Sun Microsystems Press). David has been developing object-oriented software with numerous object-oriented languages for 18 years. Since the GOF Design Patterns book was published in 1994, David has been an active proponent of design patterns and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert group defining the JSP Standard Tag Library, and is a contributor to the Apache Struts JSP framework. He writes JavaWorld's Java Design Patterns column.
Resources
• Download the source code that accompanies this article:
http://www.javaworld.com/jw-11-2002/jsf/jw-1129-jsf.jar
• An integration strategy for Struts and JavaServer Faces:
http://www.mail-archive.com/[email protected]/msg08457.html
• Download the JSF specification, the reference implementation, two sample applications, and a JSF tutorial from:
http://java.sun.com/j2ee/javaserverfaces
• Browse the JavaServer Pages section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-jsp-index.shtml
• Browse the Enterprise Java section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-enterprise-index.shtml
• David Geary's Java Design Patterns column in JavaWorld:
http://www.javaworld.com/columns/jw-java-design-patterns-index.shtml
• Visit JavaWorld's Enterprise Java discussion:
http://forums.devworld.com/webx?50@@.ee6b80a
• Sign up for JavaWorld's free weekly Enterprise Java email newsletter:
http://www.javaworld.com/subscribe
• You'll find a wealth of IT-related articles from our sister publications at IDG.net