JavaServer Faces 技术使Web应用程序开发变得更容易
JavaServer Faces 技术是建立web应用程序用户界面的框架标准,它是通过JCP(Java Community Process)由JSR-127专家组开发的,利用JavaServer Faces 技术所提供的程序模型,不同层次的 开发者都能够迅速并且容易的开发Web应用程序,他们只需要在一个页面上装配可重用的UI组件,链接这些组件到应用程序数据源,并且绑定客户端产生的事件到服务器端的事件处理器。
JavaServer Faces 技术所带来的巨大能力使得Web应用程序能够在服务器端处理错综复杂 的用户界面管理, 允许应用程序开发者只关注于应用程序代码。
JavaServer Faces 主要由以下组成:
· 一组API:显示UI组件并管理它们的状态、处理事件和输入校验、定义页面导航、支持国际化和访问。
· 一个JSP(JavaServer Pages™)定制标签库来表示在JSP页面上的UI组件。
这种清晰的编程模型和UI组件标签库大大减轻了建立和维护web应用程序的负担,你能够
· 绑定Client 端产生的事件到Server端应用程序代码;
· 映射页面的UI组件到Server端数据;
· 构建可重用和可扩展的UI组件;
· 在server请求生命期之上保存和恢复UI状态。
JavaServer Faces 技术的好处
· 简单易用:JavaServer Faces的简单易用源于它自身的体系机构。一方面,JavaServer Faces 技术在行为和表现之间提供了干净的分离,大部分用户,从网页设计者到组件开发者,都可以利用JavaServer Faces 技术的这个优点,使得更好的分工和获得更短的开发周期。另一方面 ,由JavaServer Faces 技术创建的用户界面处理了所有的错综复杂的界面管理,包括输入校 验、组件状态管理、页面导航和事件处理。
· 标准化:JavaServer Faces 技术是通过JCP(Java Community Process)在JSR-127下开发的, 几家著名的工具开发商是SR-127专家组的成员,他们将致力于在他们的工具中支持 JavaServer Faces 技术。
· 设备独立:JavaServer Faces 技术的设计是非常灵活的,在可扩展的UI组件类仅仅定义组件 的功能,JavaServer Faces 体系机构允许组件开发者去扩展这些组件类,从而为特定的客户 端产生他们自己的组件标签库。
什么是JavaServer Faces 应用程序
在很大程度上,JavaServer Faces应用程序就像其他的java web应用程序,他们执行在java servelet容器中,典型的它们包含:
· Java Bean 组件(在JavaServer Faces技术中成为模型对象)包含特定应用程序的功能和 数据;
· 事件监听器;
· 页面,例如JSP页面;
· Server端辅助类,例如数据库访问bean.
除了这些,JavaServer Faces应用程序还包含:
· 一个定制标签库用来在页面上显示UI组件;
· 一个定制标签库用来代表事件处理器、校验器和其它的动作;
· UI组件,是Server端有状态的对象;
· 校验器、事件处理器和导航处理器。
每个JavaServer Faces 应用程序必须包括两个定制标签库, 其中一个定制标签库定义了代表UI 组件的标签,另外一个定制标签库定义了其它核心操作,如事件处理器或校验器。这两个标签库由 JavaServer Faces实现提供。
组件标签库消除了在HTML中硬编码UI组件或其他标记语言的需要,从而产生完全的可重用组件,并且核心标签库使得在组件上注册事件、校验器和其它操作变得容易。
组件标签库可以是包含在JavaServer Faces技术参考实现中的html_basic标签库,或者你也可以 定义自己的标签库来传递定制组件或传递输出,而不是HTML。
JavaServer Faces 应用程序另外一个优点就是在页面上的UI组件在Server端被表现为有状态的对象,这使得应用程序能够处理组件的状态并且捆绑客户端产生的事件到Server端。
最后,JavaServer Faces技术允许你在单独的组件上转化和校验数据,并且在Server端数据被更 新之前报告错误。
JavaServer Faces 技术开发中的角色
因为JavaServer Faces 技术使得各部分工作可以分离,所以JavaServer Faces应用程序的开发和维护 能够迅速并且容易得进行。一个典型开发组的成员是列在下面的这些,在一些组里,有的 人可能充当以下角色中的多种,然而基于主要职责的观点来考虑JavaServer Faces技术仍旧是非 常有用的。
· 页面设计者 他们用标记语言,像HTML, 为Web应用程序设计页面,当用JavaServer Faces技术架 构时,页面设计者极有可能只单单使用标签库。
· 应用程序开发者 他们编写模型对象、事件处理器、校验器和页面导航控制,应用程序开发者也 负责一些其它的辅助类。
· 组件开发者 他们有用户界面编程经验,喜欢用某种语言创建定制组件,这些人可以直接从组件 库常见自己的组件,他们也能够扩展由JavaServer Faces技术提供的标准组件。
· 工具提供者 他们提供集成了JavaServer Faces技术的工具,使得建立Server端用户界面非常容易。
JavaServer Faces技术的主要用户是页面设计者和应用程序开发者,下一部分将要通过一个简单的 应用程序来解释页面设计者和应用程序开发者的工作。
一个简单的JavaServer Faces应用程序
这部分描述开发一个简单的 JavaServer Faces应用程序的过程,你将要了解到一个典型的 JavaServer Faces应用程序有哪些性能,以及在开发过程中每个角色负责哪部分。
开发流程
开发一个简单的 JavaServer Faces应用程序需要执行这些工作:
· 使用UI组件标签设计页面;
· 开发模型对象,这些模型对象将持有数据;
· 开发事件处理器。
这些工作可以同时进行,也可以按任何顺序,然而执行这些工作的人在开发过程中应该互相交流,例如,为了从页面上能访问模型对象,页面开发者需要知道这些模型对象的名字。在这部分的例子中,要求你猜1到10之间的一个数,第二页告诉你猜的是否正确,这个例子也检查输入的合法性。
创建页面
创建页面是页面设计者的职责。这个工作包括在页面上摆放UI组件,映射组件到模型对象数据和添加校验标签到组件。
这是带有校验标签的greeting.jsp页面:
<HTML>
<HEAD> <title>Hello</title> </HEAD>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<body bgcolor="white">
<h:graphic_image id="wave_img" url="/wave.med.gif" />
<h2>Hi. My name is Duke.
I'm thinking of a number from 0 to 10.
Can you guess it?</h2>
<jsp:useBean id="UserNumberBean"
class="guessNumber.UserNumberBean" scope="session" />
<f:use_faces>
<h:form id="helloForm" formName="helloForm" >
<h:input_number id="userNo" numberStyle="NUMBER"
modelReference="UserNumberBean.userNumber">
<f:validate_longrange minimum="0" maximum="10" />
</h:input_number>
<h:command_button id="submit" label="Submit"
commandName="submit" /><p>
<h:output_errors id="errors1" clientId="userNo"/>
</h:form>
</f:use_faces>
</HTML>
这个页面展示了你将在大多数JavaServer Faces应用程序中使用的性能:
· useBean标签
如果你了解JSP技术,jsp:useBean标签你应该很熟悉,这个标签实例化一个Server端的JavaBean组件,在这里,Bean的名字是UserNumberBean,这个Bean必须被包含在你的应用程序中,实例化Bean之后,你可以在这个页面内访问它的属性。
· form标签
form标签代表一个输入表单,允许用户输入一些数据并提交它到Server端,通常通过单击一个按钮。代表表单中的那些组件的标签嵌套在form标签里,这些标签是h:input_text 和 h:command_button.
· input_number标签
input_number标签代表一个文本域组件,用户可以输入一个数字。这个标签由两个属性:id 和 modelReference, id 属性对应于这个标签所代表的组件对象的ID,id 属性是可选的,如果 你没有包含这个属性, JavaServer Faces的实现将为你生成一个。modelReference指向模型对象属性。
· validate_longrange标签
input_text标签也包含一个validate_longrange标签,这是 JavaServer Faces中标准校验标 签之一,这个校验器检查组件的本地值是否在某个区域内,这个值必须能被转化为long型。 validate_longrange标签由两个属性,一个指定最大值,一个指定最小值,这里,这个标签用来确保文本域输入的必须是一个0到10的数字。
· command_button标签
command_button标签代表一个按钮,用来提交输入到文本域的数据。
· output_errors标签
output_errors标签将显示一个错误信息,如果输入到文本域的数据不符合校验器定义的规则,output_errors标签放到页面上任何地方错误信息都将显示,clientId属性指向值校验失败的组件。
下一部分讨论在这个例子中使用的模型对象。
开发模型对象
开发模型对象是应用程序开发者的职责。页面设计者和应用程序开发者可能需要协同工作以确保组件标签指向正确的对象属性,对象属性有正确的属性,并且还要注意一些其它的细节。
这是UserNumberBean类,它持有greeting.jsp页上文本域的数据。
package guessNumber;
import java.util.Random;
public class UserNumberBean {
Integer userNumber = null;
Integer randomInt = null;
String response = null;
public UserNumberBean () {
Random randomGR = new Random();
randomInt = new Integer(randomGR.nextInt(10));
System.out.println("Duke’s Number: "+randomInt);
}
public void setUserNumber(Integer user_number) {
userNumber = user_number;
System.out.println("Set userNumber " + userNumber);
}
public Integer getUserNumber() {
System.out.println("get userNumber " + userNumber);
return userNumber;
}
public String getResponse() {
if(userNumber.compareTo(randomInt) == 0)
return "Yay! You got it!";
else
return "Sorry, "+userNumber+" is incorrect.";
}
}
和你看到的一样,这个Bean和任何JavaBean组件没有什么分别:它有一组访问方法并且每个属性对应一个私有数据域,这意味着你可以从你的JavaServer Faces页面引用你写好的Bean。一个特定 的模型对象属性可以被各种组件引用,模型对象属性可以是任何基本和参考类型,这包括:Number 、 String、 int、 double和float。 JavaServer Faces技术将自动转换数据到模型对象属性指定的类 型,你可以应用一个转化器(Converter)到组件来转换组件的值到一个它不支持的类型。
在UserNumberBean中,userNumber属性是整形类型(Integer),当你使用input_number标签更新模型对象这个属性时, JavaServer Faces实现能够将包含这个值的字符串请求参数转换成整形。
处理事件
应用程序开发者另外一个职责就是为组件事件和应用程序事件写事件处理器,组件事件如选择一个checkbox、点击一个 button,应用程序事件如提交一个表单(form)。
最简单的多页应用程序中,当一个表单被提交或访问一个链接时需要定义哪页要被访问,应用程序开发者通过定义ApplicationHandler类来为应用程序定义导航器。
这是用在guessNumber例子中的 BasicApplicationHandler:,
...
public class BasicApplicationHandler implements
ApplicationHandler {
...
if (facesEvent instanceof FormEvent) {
FormEvent formEvent = (FormEvent) facesEvent;
if (formEvent.getCommandName().equals(“submit”)) {
treeId = “/response.jsp”;
}
...
}
}
这一小段代码检查是否FormEvent是由greeting.jsp页面的提交按钮产生的,如果是,组件树的ID将被设为关联response.jsp页面的组件树。
下一部分将要解释 JavaServer Faces页面是怎样被处理的。
JavaServer Faces页面的生命周期
JavaServer Faces页面的生命周期和JSP页面的相似,Client端产生HTTP请求,Server端以HTML页面 回应,但是因为JavaServer Faces提供额外的性能,在整个生命周期中,通过执行这些额外的性能,会 提供一些额外的服务。
在生命周期中,那一部被执行取决于是不是JavaServer Faces应用程序已经产生请求和是不是在 JavaServer Faces生命周期的传递阶段响应已经产生。这部分首先解释了不同的生命周期场景,然后用 guessNumber这个例子解释了生命周期中的每一阶段。
请求处理生命周期场景
JavaServer Faces应用程序支持两种不同的响应和两种不同的请求:
· JavaServer Faces响应:请求处理生命周期中传递响应阶段执行时创建的Servlet响应。
· 非JavaServer Faces响应:不是传递响应阶段执行时创建的Servlet响应,一个例子就是没有 JavaServer Faces组件的JSP页面。
· JavaServer Faces请求:由先前产生的JavaServer Faces响应发送的Servlet请求。一个例子就是从JavaServer Faces用户界面组件提交表单,请求的URI标识处理这个请求的JavaServer Faces组件树。
· 非JavaServer Faces请求:发送到应用程序的Servlet请求,例如Servlet或JSP页面,而不是指到JavaServer Faces组件树。
这些不同的请求和响应使得JavaServer Faces应用程序存在三种可能的生命周期场景:
· 场景1:非JavaServer Faces请求产生JavaServer Faces响应
这个场景的一个例子就是点击HTML页面上的超链打开一个包含 JavaServer Faces组件的页面 。从一个非 JavaServer Faces请求传递一个 JavaServer Faces响应,应用程序必须映射URL 中的FacesServlet到包含 JavaServer Faces组件的页面,FacesServlet接受请求并传递它们到生命周期的执行中。
· 场景2:JavaServer Faces请求产生非JavaServer Faces响应
有时候 JavaServer Faces应用程序可能需要重定向到不同的Web应用程序或产生一个不 包含JavaServer Faces组件的响应,在这种情况下,开发者必须从应用程序处理中调用 FacesContext.responseComplete方法来忽略传递阶段(Render Response)。FacesContext 包含关联到特定 JavaServer Faces请求的所有信息,这个方法可以在应用请求值、处理校验或更新模型值 阶段被调用。
· 场景3:JavaServer Faces请求产生JavaServer Faces响应
这是JavaServer Faces应用程序最普通的场景。这个场景包括JavaServer Faces组件利用 FacesServlet提交到JavaServer Faces应用程序,因为请求被JavaServer Faces实现处理, 所以应用程序产生响应不需要任何额外的步骤,所有的事件监听器、校验器和应用程序处理器在标准生命周期的恰当阶段被自动调用。这些将要在下一部分描述。
标准请求处理生命周期
标准的请求处理生命周期就是上一部分所描述的场景3。大部分的 JavaServer Faces技术用户并不 需要关心请求处理生命周期。
图2说明了 JavaServer Faces请求-响应生命周期。
图2:JavaServer Faces请求-响应生命周期
重建请求树
当一个 JavaServer Faces页面请求产生时,例如点击链接或按钮, JavaServer Faces实现开 始进入重建组件树阶段。在这个阶段, JavaServer Faces实现建立 JavaServer Faces页面的组件 树,捆绑事件处理器和校验器,保存组件树到FacesContext。guessNumber例子中greeting.jsp页面的组件树从概念上看起来像这样:
图3:guessNumber组件树
应用请求值
一旦组件树已经建立,组件树上的每个组件都将通过自身的decode方法从请求参数中提取新值,这个新值将被保存在组件上,如果这个值转换失败,一个关联到这个组件的错误信息将产生并排队在FacesContext上,这个错误信息将和校验阶段的校验错误信息一起在传递响应阶段被显示。
在这个阶段,如果有事件排列,JavaServer Faces实现将广播事件到感兴趣的监听器。
greeting.jsp页面userNumber组件的值是区域内输入的任何值,因为绑定组件的模型对象属性是整形类型,JavaServer Faces实现转换一个字符串到整形。
在这个时候,组件被设置新值,消息和事件已经被排列。
处理校验
在这个阶段,JavaServer Faces实现处理所有注册到树上组件的校验,它检查被指定校验规则的属性,将这些规则和保存在组件上的本地值比较,如果本地值是无效的,JavaServer Faces实现 添加一条错误信息到FacesContext.上,并且生命周期直接到传递响应阶段,带有错误信息显示的页面再一次被传递,如果在应用请求值时有转换错误,这些错误信息也将被显示。
在这个阶段,如果有事件排列,JavaServer Faces实现将广播事件到感兴趣的监听器。
在greeting.jsp页面,JavaServer Faces实现处理在userNumber input_text标签上的校验器, 它校验用户输入在文本域的数据是一个0到10的整数,如果数据是无效的或在应用请求值阶段发生转换错误,处理将跳到传递响应阶段,显示有校验和转换错误信息greeting.jsp页面再次被传递。
更新模型值
如果JavaServer Faces实现确定数据是有效的,它将遍历组件树并设置组件的本地值到相应的模型对象,仅仅有modelReference表达式的输入组件才会被更新。如果本地数据不能被转换到模型对象属性所指定的类型,生命周期将直接跳到传递响应阶段,带有错误信息显示的页面再次被传递,类似于校验错误发生。
在这个阶段,如果有事件排列,JavaServer Faces实现将广播事件到感兴趣的监听器。
在这个阶段,UserNumberBean的userNumber属性被设置为userNumber组件的本地值。
调用应用程序
在这个阶段JavaServer Faces实现处理任何应用程序级事件,例如提交表单或链接另一页。
在guessNumber例子中,greeting.jsp页面有一个应用程序级事件,它关联在Command 组件上。 当处理这个事件时,JavaServer Faces实现根据BasicApplicationHandler来决定哪一页需要被显示 ,然后产生这个新页的响应组件树,最后,JavaServer Faces实现传递控制到传递响应阶段。
传递响应
在传递响应阶段,JavaServer Faces实现调用组件的encoding功能,并传递保存在 FacesContext的组件树上组件。
如果在应用请求阶段、处理校验阶段或更新模型值阶段遇到错误,初始页面在这阶段将要被传递,如果页面包含output_errors标签,任何被排列的错误信息都将被显示在页面上。如果应用程序包含定制的传递器,这个定制器定义怎样传递一个组件,那么新的组件能被加到组件树上。树的内容被传递之后,树将被保存,这样使得后面的请求能访问它,并且在重建组件树阶段它能够被利用。
结论
JavaServer Faces 技术提供了一个简单的编程模型,使得开发Web应用程序变的更加简单,真正 体现了MVC模式,利用JavaServer Faces技术所提供的程序模型,不同层次的开发 者都能够迅速并且 容易的开发Web 应用程序。
参考资料
JavaServer Faces 技术网站
http://java.sun.com/j2ee/javaserverfaces
关于作者
王国军 从事软件开发工作,对Java技术很感兴趣,目前从事Workflow系统的开发工作。您可以直接通过 E-Mail : wangguojun@vip.sina.com 与他联系!