from:http://gceclub.sun.com.cn/staticcontent/html/jsf/article/jsf03.html
作者:Qusay H. Mahmoud
在创建服务器端应用程序的用户界面时,有多种可供选择的技术。使用servlet或JSP的Java开发人员通常依靠HTML用户界面组件来开发用户界面,这主要是因为HTML用户界面组件要得到各种Web浏览器的支持。当然,这也意味着与独立的胖客户端程序相比,这种Web应用程序不会拥有丰富的用户界面,因而其功能更少,可用性也更差。可以使用Applet来开发功能丰富的用户界面,不过页面开发人员可能并不熟悉(或者没有兴趣学习)Java语言。
另外,如果参与过大规模的Web系统的开发,你可能已经经历过很多技术性的挑战。例如如何实现客户组件,像查询建立器,或是为数据库查询实现表浏览器。建立这样的客户组件要求有这方面专家,并且要花大量的时间建立和测试这些新的库。在理想的环境中,开发人员应该可以使用已经预先建立,经过测试,并且高度可配置的组件,使之集成在他们的开发环境中。
JavaServer Faces是一种服务器端技术,用于开发具有丰富用户界面的Web应用程序。使用JavaServer Faces ,像创建客户界面组件之类的挑战可以得到解决。这是因为JavaServer Faces技术是一种用户界面框架,用来建立运行在服务器端并将用户界面返回给客户端的Web应用程序。这就对了,用户界面代码运行在服务器上,对客户端产生的事件作出响应。
现在还有一些其他的选择可以建立丰富的服务器端用户界面,如Flash,Swinglets,以及Jade。然而,这些解决方案是私有的,并且支持这些开发的工具通常只能从某个唯一的供应商那里获得。与之不同的是,JavaServer Faces是一个标准,这意味着开发人员不会被锁定在某一个工具供应商上。在Java社区中,规范专家组由来自所有主要的工具供应商的专家组成。因而,开发人员不会缺少工具,并且更有可能获得现在使用的工具的升级版本。当工具供应商在规范上进行合作时,他们将在工具实现上进行竞争。开发人员将从中受益,供应商们会提供各种客户组件和更多的特性供他们选择。
JavaServer Faces技术基于模式-视图-控制器(Model View Controller ,MVC),以便将逻辑和表示分离。如果你已经在这方面有了经验,那么对于JavaServer Faces可能会有某种熟悉的感觉。
本文提供了一个简明扼要且代码丰富的教程,带你进入JavaServer Faces。本文另外还:
请注意本教程没有演示如何开发自定义组件。
JavaServer Faces概览
JavaServer Faces是Java Community Process (JCP) 在Sun Microsystems的领导下开发的一种技术,在JCP中编号为JSR 127。它的目标是为Web应用程序的用户界面创建一个标准框架。前面提到,JavaServer Faces让你可以建立运行在Java服务器上的Web应用程序,并将用户界面呈现给客户端。这种技术通过一个控制器Servlet提供Web应用程序生命周期管理,并提供具有事件处理和组件呈现的丰富组件模型。
JavaServer Faces技术有两个主要组成部分:
图1显示了客户端,服务器,以及JavaServer Faces之间的关系。
图1:运行在服务器上的UI
在这里,JSP页面表示使用JavaServer Faces自定义标签库的用户界面组件,而不是将它们硬编码进标记语言中。应用程序的UI管理着JSP页面呈现的对象。
下面几种用户可以受益于这种技术:
这种技术还开辟了一个可重用Web用户界面组件的市场。开发人员和供应商可以使用JavaServer Faces作为开发客户界面的建立模块。
JavaServer Faces优点之一是它是基于模式-视图-控制器体系统结构(Model View Controller ,MVC)的,可以将表示和逻辑清晰地分离。正在使用现有Web框架如Struts的开发人员可能会对此感到熟悉。然而,注意JavaServer Faces和Structs不是互相竞争的技术,事实上,它们将会互相补充。不过,JavaServer Faces的确比Structs具有某些优势。例如,在Structs中只有一种呈现元素的方式,而JavaServer Faces提供了几种机制来呈现独立的元素。由页面设计者选择他们想要的表示方式,而应用程序开发人员不必知道使用哪种机制来呈现组件(从http://jakarta.apache.org/struts/proposals/struts-faces.html可以了解更多信息)。读者也许注意到Structs的设计者,Craig McClanahan也是制定JavaServer Faces规范的领导者之一,他也是Sun Microsystems的雇员。
JavaServer Faces应用程序的起源
JavaServer Faces应用程序就像任何其他基于Java技术的Web应用程序一样,它运行在一个Java Servlet容器中,包括:
JavaServer Faces参考实现中包含一个组件标签库,html_basic。然而,高级开发人员可以开发他们自己的标签库,以便呈现自定义的组件。
JavaServer Faces参考实现提供了一个自定义的标签库,用于在HTML中呈现组件。下面是一个使用这个标签库的简单例子。如果想得到它支持的组件标签清单,请参考JavaServer Faces的 规范 和 教程。
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <body bgcolor="white"> <h2>What is your name?</h2> <f:use_faces> <h:form id="helloForm" formName="helloForm" > <h:input_text id="username" /> <h:command_button id="submit" label="Submit" commandName="submit" /> </h:form> </f:use_faces> |
JavaServer Faces组件的体系结构是这样设计的:组件的功能由组件类定义,组件的呈现由一个单独的呈现器(renderer)定义。一个呈现器工具定义了组件类如何映射为适合特定客户的组件标签。JavaServer Faces参考实现中包含一个标准的RenderKit,用于将组件类呈现给HTML客户。HTML RenderKit中的每个JSP组件的组件功能由UIComponent类定义,组件的呈现属性由Renderer类定义。例如,标签command_button和command_hyperlink都表示一个UIComponent,但是它们是用不同的方式呈现的。Button组件呈现为一个按钮,而hyperlink呈现为一个超链接。
JavaServer Faces初步
要开始试用JavaServer Faces,需要安装Java Web Services Developer Pack (Java WSDP 1.0_01)或者Tomcat4.0+。 JavaServer Faces参考实现Early Access release (EA3)可以从以下网址下载: http://java.sun.com/j2ee/javaserverfaces/download.html。解压下载的文档后,在Windows下将得到下面的目录结构:
c:\jsf-ea3> example lib some-other-files
example目录包含示例应用程序的WAR和源文件。lib目录包含JavaServer Faces所依赖的JAR文件,这些文件是:
请记住JavaServer Faces参考实现是一个早期访问版本(EA),而且仅仅是JavaServer Faces规范的一个快照。换句话说,这个版本是不成熟的。还要注意当前的JavaServer Faces参考实现(RI)无法与Java WSDP 1.1协同工作。如果试图将它和Java WSDP 1.1一起使用,将会得到图2所示的异常:
图2:JavaServer Faces RI EA无法与Java WSDP 1.1协同工作。(点击放大)
如果没有Java WSDP 1.0_01,并且想实验JavaServer Faces RI EA3,我推荐使用Tomcat。在本文中,我使用Tomcat-4.1.24。一旦安装好Tomcat,启动它并在浏览器中输入http://localhost:8080以测试它(是否工作正常)。你应该能看到Tomcat的缺省页面。现在,要实验某个JavaServer Faces示例应用程序,只需将它们的WAR文件(从c:\path-to-JSF-installation)复制到Tomcat安装目录下的webapps中。要运行应用程序,在浏览器中输入http://localhost:8080/demo-name。例如,我将cardemo.war复制到Tomcat的webapps目录中,并在我的浏览器中输入http://localhost:8080/cardemo。图3是我得到的页面的一幅快照。
图3:JavaServer Faces cardemo示例应用程序。(点击放大)
创建自己的应用程序
这一节将介绍创建自己的应用程序的步骤。我在这里使用的例子是一个简单的窗体,它要求用户输入他或她的名字,然后单击Submit 按钮。应用程序将向用户显示一条问候消息。
c:\tomcat4.1\webapps hello src (for Java files) web (for web files: index.html and JSP pages...) WEB-INF web.xml lib (JSF JAR files) classes |
这个结构主要说明我将创建一个名为hello的新应用程序。在hello子目录下,我创建了src(我在这里存放所有的Java源文件)和web(这里有WEB-INF子目录,它包含web.xml,以及lib子目录和classes子目录)。
代码示例1: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> <listener> <!-- Used to initialize and destroy the application helper and register a Renderer to a RenderKit --> <listener-class>BasicServletContextListener</listener-class> </listener> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <!-- FaceServlet should be loaded when the application starts up --> <load-on-startup>1</load-on-startup> </servlet> <!-- Faces Servlet Mapping. Map the path to the servlet when a request for the servlet is received --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app> |
首先我将编写index.html页面。当用户进入应用程序时,他们得到的就是这个页面,它允许用户单击应用程序启动它。如代码示例2所示:
代码示例2:index.html
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta name="GENERATOR" content="Mozilla/4.75 [en] (WinNT; U) [Netscape]"> <title>index</title> </head> <body> <P>Click <a href="/developer/technicalArticles/GUI/JavaServerFaces/faces/index.jsp">here</a> to start the application.</P> <br> <hr WIDTH="100%"> </body> </html> |
当用户单击"here",就会载入index.jsp页面,如代码示例3所示:
代码示例3:index.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"> <h2>What is your name?</h2> <jsp:useBean id="UserNameBean" class="UserNameBean" scope="session" /> <f:use_faces> <h:form id="helloForm" formName="helloForm" > <h:input_text id="username" modelReference="UserNameBean.userName"/> <h:command_button id="submit" label="Submit" commandName="submit" /> </h:form> </f:use_faces> </HTML> |
这个JSP页面使用了一些重要的特性:
模型对象bean和所有其他JavaBean组件一样,它拥有一组访问器方法。代码示例4展示了一个JavaBean组件的例子,代码示例3中的index.jsp页面中引用了它。
代码示例4:UserNameBean.java
public class UserNameBean { String userName = null; public UserNameBean () { } public void setUserName(String user_name) { userName = user_name; } public String getUserName() { return userName; } } |
下一步是为组件事件(如选中一个复选框或单击一个按钮以提交表单)编写一个事件处理程序类。对于简单的应用程序,需要定义当表单提交或访问链接时应该访问哪一个页面。可以通过实现ApplicationHandler接口来完成。代码示例5显示了一个例子。在这里,程序检查FormEvent事件是否是由index.jsp页面中的Submit按钮产生。如果是,组件树的ID被设置为与index.jsp页面相关联的组件树。
代码示例5:BasicApplicationHandler.java
import java.util.SortedMap; import javax.faces.FacesException; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.tree.Tree; import javax.faces.tree.TreeFactory; import javax.faces.FactoryFinder; import javax.faces.lifecycle.ApplicationHandler; import javax.faces.event.FormEvent; import javax.faces.event.FacesEvent; import javax.faces.event.CommandEvent; import com.sun.faces.RIConstants; public class BasicApplicationHandler implements ApplicationHandler{ public boolean processEvent(FacesContext context, FacesEvent facesEvent) { if (!(facesEvent instanceof FormEvent) && !(facesEvent instanceof CommandEvent)) { return true; } boolean returnValue = false; String treeId = null; if (facesEvent instanceof FormEvent) { FormEvent formEvent = (FormEvent) facesEvent; if (formEvent.getCommandName().equals("submit")) { treeId = "/hello.jsp"; } returnValue = true; } else if (facesEvent instanceof CommandEvent) { CommandEvent commandEvent = (CommandEvent)facesEvent; UIComponent c = commandEvent.getComponent(); if (c.getAttribute("target") != null) { treeId = (String)c.getAttribute("target"); returnValue = true; } } if (null != treeId) { TreeFactory treeFactory = (TreeFactory) FactoryFinder.getFactory(FactoryFinder.TREE_FACTORY); context.setTree(treeFactory.getTree(context,treeId)); } return returnValue; } } |
如果仔细观察部署描述符文件web.xml,将会发现我声明了一个servlet上下文监听器(BasicServletContextListener)。servlet容器在应用程序启动时调用监听器的contextInitialized方法,创建一个servlet上下文监听器;当应用程序关闭时,调用监听器的contextDestroyed方法。代码示例6展示了一个上下文监听器的例子。
代码示例6:BasicServletContextListener.java
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent; import javax.faces.FactoryFinder; import javax.faces.lifecycle.LifecycleFactory; import javax.faces.lifecycle.Lifecycle; import javax.faces.lifecycle.ApplicationHandler; public class BasicServletContextListener implements ServletContextListener { public BasicServletContextListener() { } public void contextInitialized(ServletContextEvent e) { ApplicationHandler handler = new BasicApplicationHandler(); LifecycleFactory factory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); Lifecycle lifecycle = factory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); lifecycle.setApplicationHandler(handler); } public void contextDestroyed(ServletContextEvent e){ } } |
当index.jsp中的表单提交之后,应用处理程序被调用,用户进入到响应页面,hello.jsp,如代码示例7所示:
代码示例7:hello.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"> <f:use_faces> <h:form id="responseform" formName="responseform"> <h2>Hello, <h:output_text id="userLabel" modelReference="UserNameBean.userName" /> </h2> <p> </h:form> </f:use_faces> </HTML> |
图4:进入应用程序
当单击"here"超链接,将会得到类似于图5所示的页面。
图5:开始应用程序
现在,输入你的名字并单击Submit按钮,将得到类似于图6所示的页面。
图6:正确运行的应用程序
输入验证
JavaServer Faces提供了一组标准的内置验证机制(或称验证程序),通过实现Validator 接口及其validate方法,允许开发人员创建自定义的验证程序。这五个内置的验证程序是:
<input_number id="less" formatpattern="#.## size="5"> <validate_doublerange minimum="1.0" maximum="3.14"/> </input_number>
<input_text id="creditCardNum" size="16"> <validate_length minimum="16" maximum="16"/> </input_text>
<h:input_number id="zip" formatpattern="#####" size="5"> <validate_longrange minimum="50000" maximum="10000"/> </input_number>
<input_text id="creditCardNum" size="16"> <validate_required/> <validate_length minimum="16" maximum="16"/> </input_text>
<input_text id="middleInitial" size="1"> <validate_stringrange minimum="A" maximum="Z"/> </input_text>
结论
JavaServer Faces是一个用户界面框架,用于构建运行在服务器端的Web应用程序,并将用户界面返回给客户端。使用它可以开发一些工具,简化基于Web的Java应用程序编程。Sun和JavaServer Faces专家组的其他成员,包括Borland,IBM,Macromedia 以及Oracle,以及许多其他公司和个人,正在评估将JavaServer Faces技术结合进新一代工具中的途径,这些工具将简化基于Web的多层应用程序的开发。
JavaServer Faces控件提供了广泛的用户交互方式,使用基于JavaServer Faces的应用程序的用户会喜欢这些。与标准的HTML前端相比,它可以提供更多的特性,使用更加方便。记住,与普通的JSP配置相比,使用JavaServer Faces需要做更少,而得到的益处却多得多。