用JavaServer Faces开发Web应用程序[转]

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的优点。
  • 介绍了JavaServer Faces的内部机制。
  • 介绍了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. 用于表示UI组件,管理状态,处理事件,验证输入的Java API。这组API还支持国际化和可访问性。
  2. JSP自定义标签库,用于在JSP页面中表达JavaServer Faces。页面设计者可以使用这个标签库将UI组件加入到页面中。

图1显示了客户端,服务器,以及JavaServer Faces之间的关系。

图1:运行在服务器上的UI

在这里,JSP页面表示使用JavaServer Faces自定义标签库的用户界面组件,而不是将它们硬编码进标记语言中。应用程序的UI管理着JSP页面呈现的对象。

下面几种用户可以受益于这种技术:

  • 使用标记语言如HTML的页面设计人员,将使用JSP标签库来表示JavaServer Faces中丰富的用户界面组件。
  • 编写模型对象和事件处理程序的应用程序开发人员。
  • 组件开发人员,用于创建基于JavaServer Faces组件的自定义组件。
  • 在工具中提供JavaServer Faces支持的工具供应商,将JavaServer Faces技术集成在新一代工具中简化了多层的、基于Web的应用程序的开发过程。

这种技术还开辟了一个可重用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容器中,包括:

  1. 包含特定于应用程序功能和数据的JavaBeans组件(或模型对象)。
  2. 事件监听器。
  3. JSP页面。
  4. 服务器端帮助器类。
  5. 用于表示UI组件的自定义标签库。
  6. 用于表示事件处理程序和有效性验证程序的自定义标签库。
  7. UI组件在服务器上表示为有状态的对象。
  8. 事件处理程序、有效性验证程序、以及导航处理程序。(有效性验证程序用于在更新服务端数据之前,验证各个组件中的数据的有效性。)

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文件,这些文件是:

  • commons-beanutils.jar:定义和访问JavaBeans组件属性的实用工具。
  • commons-collections.jar:J2SE集合框架的扩展。
  • commons-digester.jar:用于处理XML文档。
  • commons-logging.jar:一个通用的、灵活的日志工具,允许开发人员用日志语句来调试(instrument)他们的代码。
  • jsf-api.jar:包含javax.faces.* API类。
  • jsf-ri.jar:包含JavaServer Faces Reference Implementation的实现类。
  • jstl.jar:包含JavaServer Faces Standard Tag Library classes(JSTL)。
  • jstl_el.jar:包含处理JSTL表达式语句的类。
  • standard.jar:使用JSTL时需要用到它。

请记住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 按钮。应用程序将向用户显示一条问候消息。

  1. 创建下面的目录结构:
    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子目录)。

  2. 从c:\jsf-ea3\lib中将所有的JAR文件复制到上面创建的lib子目录中。
  3. 创建一个web.xml,它用来配置Web应用程序。在JavaServer Faces中,它必须指定某些配置,如:(1)servlet上下文监听器,(2)用来处理在JavaServer Faces请求的servlet,以及(3)处理servlet的servlet映射。代码示例1显示了一个web.xml文件的例子,它定义了本例中的JavaServer Faces所需的配置。

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

  4. 创建带有JavaServer Faces标签的HTML文件。

    首先我将编写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页面使用了一些重要的特性:

    • 自定义标签库。组件标签库免去了在HTML中硬编码UI组件,结果得到的是可重用的组件。而且核心标签库使得注册组件的事件和其他操作变得很容易。
    • <jsp:useBean>标签用来例示一个名为UserNameBean的JavaBeans组件,这个组件接下来在服务器上实现。
    • form标签用来表示一个输入表单,这个标签用来表示表单组件,form标签中嵌套了input_text和command_button。
    • input_text标签表示一个文本域,用户在其中输入一个字符串。这个标签具有两个属性:id和modelReference。id与组件对应,它是可选的。modelReference引用模型对象属性,它保存着输入到文本域中的数据。
    • command_button表示一个按钮,它用来提交输入到文本域中的数据。
  5. 如果需要的话,编写模型对象(JavaBean组件)。

    模型对象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;
                    }
                    }
                    

  6. 处理事件。

    下一步是为组件事件(如选中一个复选框或单击一个按钮以提交表单)编写一个事件处理程序类。对于简单的应用程序,需要定义当表单提交或访问链接时应该访问哪一个页面。可以通过实现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;
                    }
                    }
                    

  7. 编写上下文监听器。

    如果仔细观察部署描述符文件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){
                    }
                    }
                    

  8. 编写一个响应页面。

    当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>
                    

  9. 编译和运行应用程序。最后一步是编译Java类和运行应用程序。在Web浏览器中输入URL:http://localhost:8080/hello,将得到如图4所示的index.html。

    图4:进入应用程序

    当单击"here"超链接,将会得到类似于图5所示的页面。

    图5:开始应用程序

    现在,输入你的名字并单击Submit按钮,将得到类似于图6所示的页面。

    图6:正确运行的应用程序

    输入验证

    JavaServer Faces提供了一组标准的内置验证机制(或称验证程序),通过实现Validator 接口及其validate方法,允许开发人员创建自定义的验证程序。这五个内置的验证程序是:

    1. DoubleRangeValidator:检查组件的值是否在某个范围之内。值必须是一个浮点数,或者可以转换为一个浮点数。通过validate_doublerange标签可以使用这个验证程序。下面是一个例子:
      <input_number id="less" formatpattern="#.## size="5">
                  <validate_doublerange minimum="1.0" maximum="3.14"/>
                  </input_number>
                  
    2. LengthValidator:检查值(必须是javalang.String类型)的长度是否在某个特定的范围之内,通过validate_length标签使用这个验证程序。下面是一个例子:
      <input_text id="creditCardNum" size="16">
                  <validate_length minimum="16" maximum="16"/>
                  </input_text>
                  
    3. LongRangeValidator:检查值(任何可以转化为long的类型)的长度是否在某个特定的范围之内,通过validate_ longrange标签使用这个验证程序。下面是一个例子:
      <h:input_number id="zip" formatpattern="#####" size="5">
                  <validate_longrange minimum="50000" maximum="10000"/>
                  </input_number>
                  
    4. RequiredValidator:检查组件的值是否为null,如果值的类型是String,它确保组件的值不是一个空串,通过validate_ required标签使用这个验证程序。下面是一个例子:
      <input_text id="creditCardNum" size="16">
                  <validate_required/>
                  <validate_length minimum="16" maximum="16"/>
                  </input_text>
                  
    5. StringRangeValidator:检查组件的值(必须是javalang.String类型)是否在某个特定的范围之内,通过validate_ stringrange标签使用这个验证程序。下面是一个例子:
      <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需要做更少,而得到的益处却多得多。

你可能感兴趣的:(Web,应用服务器,jsp,servlet,JSF)