使用 JavaServer Faces 构建 Apache Geronimo 应用程序,第 5 部分: 将 JSF 应用程序与 Spring 集成
2010-05-12 00:00:00 来源:WEB开发网开始之前
本教程向 Java 程序员介绍如何使用 JSF 组件来构建具有高度交互性的部署在 Apache Geronimo 上的 Java EE 应用程序。本教程假设读者将使用 Eclipse IDE 作为开发平台。
关于本教程
本教程讲解 Spring Framework,这是一个大型(且非常完整的)Web 应用程序框架,可以将它与 JSF 应用程序结合使用。我们将使用 Spring 继续开发我们这个开发人员论坛示例应用程序的登录页面的前端。
关于本系列
本教程是关于使用 JSF 构建 Apache Geronimo 应用程序的系列教程(共分五部分)的最后一部分。下面是整个系列教程的摘要:
第 1 部分:使用 Eclipse 和 Apache MyFaces Core 构建基本的应用程序 介绍了如何将 JSF 标准的 Apache MyFaces 实现与免费应用服务器 Geronimo(同样来自 Apache)结合使用。这个教程向您展示了如何使用 Eclipse IDE 的 Web Tool Platform(WTP)构建 JSF 应用程序。
第 2 部分:在 JavaServer Faces 中使用 Tomahawk 展示了如何将 Apache Tomahawk 组件与 Geronimo 应用程序集成在一起。Tomahawk 提供了若干个自定义组件,可与 JSF 完全兼容。
第 3 部分:在 JavaServer Faces 中使用 ajax4jsf 展示了如何使用 Sun 的免费开放源码框架 ajax4jsf 将 Ajax 功能添加到 Geronimo 应用程序中。
第 4 部分:使用 Apache Trinidad 组件扩展 JSF 介绍了如何将来自 Apache Trinidad(ADF Faces 的开放源码版本)的组件集成到 Geronimo 应用程序中,以增强 JSF 应用程序的界面。
第 5 部分:将 JSF 应用程序与 Spring 集成 展示了如何将 JSF 应用程序与 Spring 框架集成。Spring 是一个流行的框架,它使 Geronimo 开发人员能更轻松地构建 Java EE 应用程序。
系统需求
必须具备以下工具才能学习本教程:
Geronimo,Apache 的 Java EE 服务器项目。Geronimo 提供了 Tomcat 和 Jetty 两种风格,选用哪种取决于您的需求。我们使用 Jetty(1.1 版),因为它比较小。
MyFaces,Apache 的 JSF 实现。请从 Apache 下载核心版本(不附带 Tomcat)。
Spring Framework,一个强大的应用程序框架,可以与现有的 Web 应用程序集成。
Eclipse,可扩展的开放源码 IDE,支持多种语言和平台。
Eclipse Web Tools Platform,用于向 Eclipse 中添加了 XML 和 JavaScript 编辑支持以及对 JSF 的基本支持。
在系统中安装 Java 1.4 或更高版本。Eclipse 二进制文件附带了它自己的 Java 运行时,但 Geronimo 和 MyFaces 则没有(带运行时会使下载存档文件显著变大)。在本教程中,我们使用 Mac OS X 10.4 上的 Java 1.5,但应当不会有太大差异。
准备工作
在本节中,我们将导入当前的 devSignup 项目,以便在下一节开始将 Spring 功能集成到应用程序中。您还将了解 Spring Framework 以及它的一些优点。
导入 devSignup 项目
如果您还没有阅读本系列的前几篇教程,至少应该下载 devSignup 示例项目(本教程末尾的 下载 部分提供了链接),因为稍后将需要在其中添加功能。
第 2 部分 详细说明了如何将项目从源存档文件导入 Eclipse。下载 devSignup-src.zip 并按照第 2 部分中的说明进行操作,完成后再回到这里。确保按照第 2 部分的 “修复 devSignup 项目” 一节中的说明进行操作,否则将不能构建应用程序。
完成后,Eclipse Navigator 视图应当类似于 图 1。
图 1. Eclipse 中的 devSignup 项目
现在,开始研究 Spring Framework 以及它能够为您做什么。
Spring Framework
Spring 是一个大型 Java Web 应用程序框架,专为使 Java 编程更轻松而设计。它能够很好地与 Hibernate 等现有工具相集成,并隐藏了不同 Java Database Connectivity(JDBC)实现之间的差异。它提供一个分层的设计(见 图 2)并支持一些游泳的特性,包括:
用于应用程序及其对象的完整的轻量容器
用于事务管理的通用抽象层,它不与任何特定的 Java 环境绑定,对开发人员隐藏了低层细节(和问题)
JDBC 抽象层,它跨 JDBC 实现提供有意义的标准化的异常行为
与各种资源持有程序的集成,包括 TopLink、Hibernate、Java Data Objects(JDO)和 iBATIS SQL Maps
Spring 配置管理中集成了面向方面的编程(Aspect-Oriented Programming,AOP)
灵活的 Model View Controller(MVC)Web 应用程序框架
Spring 的主要模块见 图 2。
图 2. 充满 Java EE 缩写词的 Spring 体系结构
在 图 2 中可以看到,Spring 在一个 Geronimo 应用服务器中运行,这使您能够体会它的分层设计。Spring 允许使用 JavaBean 属性和配置文件注入对象;因此可以动态地添加或删除进行协作的对象和服务。对于熟悉 Decorator 设计模式的开发人员,这种设计很相似,但是不需要任何代码重构;添加或删除对象都是通过配置文件进行的。
在 Spring 中有许多高端的企业应用特性和支持,本教程不会讨论这些内容,以使您集中关注如何在现有的应用程序中利用 Spring Framework。
回顾 devSignup 的 MyFaces JSF 实现
既然已经对 Spring 有了点儿了解,就应该看一些实际代码了。
首先,看看如何让 Developer Forum Signup 应用程序在使用 Apache MyFaces JSF 实现的 Geronimo 中运行。然后,在下一节中,将在其中添加一些 Spring 功能。
MyFaces Developer Signup 应用程序
当前,Developer Signup 应用程序相当简单。它显示一个页面,页面上有几个用户可以填写的字段,它会验证一些数据(如果探测到无效数据,就警告用户),并告诉用户操作是否成功。实际上,我们返回到本系列 第 2 部分 (“在 JavaServer Faces 中使用 Tomahawk”)中的版本,所以它只使用普通 JSF(采用 Apache MyFaces 的形式)以及几个来自 Tomahawk 组件库的扩展。这会提供少量功能,避免过大的复杂性。
这个小应用程序中最重要的文件是:
web.xml —— Java EE 应用程序描述符、设置等等
faces-config.xml —— JSF 配置
geronimo-web.xml —— Geronimo 应用程序描述符
signup.jsp —— 注册页面和验证
SignupData.java —— 跟踪表单数据的 bean
在 下载 部分中可以找到这个应用程序的基本 JSF 版本的源代码(devSignup-jsf-src.zip),可以将它装载进 Eclipse 并进行实验。现在快速浏览一下重要的源代码文件。
devSignup web.xml
清单 1 显示 Developer Signup 应用程序中完整的 web.xml 文件。
清单 1. Developer Signup 的 web.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="devSignup" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>devSignup</display-name>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.PRETTY_HTML</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ADD_RESOURCE_CLASS</param-name>
<param-value>org.apache.myfaces.renderkit.html.util.DefaultAddResource
</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.CHECK_EXTENSIONS_FILTER</param-name
>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.ADD_RESOURCE_CLASS</param-name>
<param-value>org.apache.myfaces.renderkit.html.util.DefaultAddResource
</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.CHECK_EXTENSIONS_FILTER</param-name
>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<filter>
<filter-name>MyFacesExtensionsFilter</filter-name>
<filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</fil
ter-class>
<init-param>
<param-name>maxFileSize</param-name>
<param-value>20m</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFacesExtensionsFilter</filter-name>
<url-pattern>*.faces</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>MyFacesExtensionsFilter</filter-name>
<url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
这个 web.xml 文件包含几组元素,见 表 1。
表 1. web.xml 文件中的元素
元素 | 描述 |
<web-app> | Web 应用程序描述符数据的容器 |
<display-name> | 向系统管理员显示的应用程序名 |
<context-param> | 键-值对,它们设置 Web 应用程序组件使用的各种配置值;这里显示的大多数是默认值,但也可以以任何方式指定,从而在应用程序启动日志中消除警告 |
<listener> | 指定监听器的类名,这个类将监听到来的客户机连接并决定如何处理它们 |
<servlet> | 在这里指定 servlet 的内部名称、管理 servlet 组件的类的名称以及在应用服务器启动时是否应该装载这个 servlet |
<servlet-mapping> | 定义在 <servlet-name> 指定的 <servlet> 匹配时将装载的 URL,这里的 <servlet-name> 必须与 <servlet> 部分中指定的 <servlet-name> 匹配 |
<filter> 和 <filter-mapping> | 在应用程序中添加一个页面过滤器,并指定哪些 URL 需要通过这个过滤器,就像 <servlet> 和 <servlet-mapping> 对一样 |
<welcome-file-list> | 列出一个或多个文件名,如果将不完整的 URL 传递给应用程序,就应该装载这些文件 |
这些都是标准的 Java EE 应用程序描述符标记;这里没有 JSF、MyFaces 或 Tomahawk 专用的标记。
devSignup faces-config.xml
faces-config.xml 文件(见 清单 2)设置 JSF 应用程序参数,并声明托管 bean 以及从一个 JSF 页面链接到下一个页面的导航规则。
清单 2. JSF 应用程序参数在 faces-config.xml 中设置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<application>
<locale-config>
<default-locale>en_US</default-locale>
</locale-config>
</application>
<managed-bean>
<description>
Data used for requesting membership in the Developer Forum.
</description>
<managed-bean-name>signupData</managed-bean-name>
<managed-bean-class>devSignup.SignupData</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<display-name>signup</display-name>
<from-view-id>/signup.jsp</from-view-id>
<navigation-case>
<from-outcome>signup-success</from-outcome>
<to-view-id>/signup-success.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<display-name>signup</display-name>
<from-view-id>/signup.jsp</from-view-id>
<navigation-case>
<from-outcome>signup-failure</from-outcome>
<to-view-id>/signup-failure.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
这个文件的元素(见 表 2)比 web.xml 中的元素复杂一点儿,但是可以通过 Eclipse Web Tooling Platform 的图形化编辑器创建其中的大多数元素。
表 2. faces-config.xml 文件中的元素
元素 | 描述 |
<faces-config> | JSF 应用程序数据的容器 |
<application> | 允许指定应用程序设置、支持的语言等等 |
<managed-bean> | 每个 <managed-bean> 标记定义和描述应用程序使用的一个托管 bean,包括在 JavaServer Pages(JSP)页面中引用它的名称、实现这个 bean 的 Java 类的名称以及 bean 的作用范围。 |
<navigation-rule> | 每个 <navigation-rule> 指定一个源页面、一个响应字符串(这来自从源页面调用的 bean 中的一个方法)以及与这个响应对应的目标页面。 |
我发现 <navigation-rule> 块有点繁冗;我认为,应该允许每个 <navigation-rule> 中有多个 <navigation-case> 元素的,那会使代码更清晰,但 JSF 不是我设计的。
devSignup geronimo-web.xml
geronimo-web.xml 文件相当简单(见 清单 3),它表示在服务器上通过哪个 URL 显露应用程序。
清单 3. Geronimo 将应用程序放在哪里(geronimo-web.xml)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1"
xmlns:naming="http://geronimo.apache.org/xml/ns/naming">
<context-root>/devSignup</context-root>
</web-app>
很简单,不是吗?
devSignup signup.jsp
在 清单 4 中可以看到,Developer Signup 输入表单相当简单,它只使用了文本输入字段和一些基本的 Tomahawk 验证器组件。
清单 4. Developer Signup 输入表单
<?xml version="1.0" encoding="UTF-8" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:t="http://myfaces.apache.org/tomahawk">
<jsp:output omit-xml-declaration="false" doctype-root-element="html"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" />
<jsp:directive.page contentType="text/html;charset=utf-8" />
<f:view>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"
/>
<title>Developer Forum Signup</title>
</head>
<body>
<h1>Developer Forum Signup</h1>
<p>Welcome to our forums! Please fill in the following form
to create your forum account.</p>
<h:form>
<dl>
<dt>Screen name:</dt>
<dd><h:inputText value="#{signupData.screenName}"
/></dd>
<dt>Email:</dt>
<dd><h:inputText value="#{signupData.email}"
id="email" required="true">
<t:validateEmail />
</h:inputText><br />
<strong><h:message for="email"
/></strong></dd>
<dt>Password:</dt>
<dd><h:inputSecret value="#{signupData.password}"
id="password" required="true" /></dd>
<dt>Password (for verification):</dt>
<dd><h:inputSecret id="password_verify"
required="true">
<t:validateEqual for="password" />
</h:inputSecret><br />
<strong><h:message for="password_verify"
/></strong></dd>
<dt>Birthday:</dt>
<dd><t:inputDate id="birthday"
value="#{signupData.birthday}" popupCalendar="true"
/></dd>
</dl>
<h:commandButton action="#{signupData.register}">Sign
up</h:commandButton>
</h:form>
</body>
</html>
</f:view>
</jsp:root>
这与本系列 第 2 部分 中的 signup.jsp 稍有差异;这个版本使用 XML 语法而不是 JSP 语法。(我喜欢格式良好的 XML!)
devSignup SignupData.java
最后是这个应用程序中使用的托管 bean 的源代码(见 清单 5)。
清单 5. Developer Signup 应用程序的托管 bean
package devSignup;
public class SignupData {
// Properties and accessors.
private String _screenName = "nobody";
private String _email = "nobody@company.com";
private String _password = "";
private java.util.Date _birthday = null;
public SignupData() {
this._birthday = new java.util.Date();
}
public java.util.Date getBirthday() {
return this._birthday;
}
public void setBirthday(java.util.Date newBirthday) {
this._birthday = newBirthday;
}
public String getScreenName() {
return this._screenName;
}
public void setScreenName(String newScreenName) {
this._screenName = newScreenName;
}
public String getEmail() {
return this._email;
}
public void setEmail(String newEmail) {
this._email = newEmail;
}
// NOTE: THIS IS NOT SECURE, DON'T DO THIS
// WITH YOUR PASSWORDS!
public String getPassword() {
return this._password;
}
public void setPassword(String newPassword) {
this._password = newPassword;
}
// The registration attempt handler.
public String register() {
if ((this._email == null) || (this._screenName == null)
|| (this._password == null)) {
// Bad code? lost data?
return "signup-failure";
}
if ((this._email.trim().length() < 3)
|| (this._email.indexOf("@") == -1)) {
// Bad email address.
return "signup-failure";
}
if (this._password.trim().length() < 8) {
// Password too short.
return "signup-failure";
}
return "signup-success";
}
}
这个简单的 bean 管理从表单收集的所有数据。它还提供一个方法 register(),当用户点击 Sign up 按钮时从表单调用这个方法。它返回前面在 faces-config.xml 文件中看到响应字符串之一。JSF 引擎使用这些响应字符串判断接下来要显示哪个页面。
既然已经回顾了 Developer Signup 应用程序的 MyFaces 版本,下面就讨论如何添加 Spring 功能。
在 devSignup 中添加 Spring MVC
现在 devSignup 已经准备好添加 Spring MVC 功能了,我们马上开始。
开始
在 Eclipse 的 Navigator 视图中右击 devSignup 项目,然后从上下文菜单中选择 Properties。Eclipse 显示 Properties 对话框。
点击列表中的 JSF Library References 显示 JSF Library References 面板(见 图 3)。
图 3. 在 devSignup 项目中添加 Spring
点击选择列表区域中的 New 按钮(不是 Implementation Library 下拉列表旁边的按钮),显示 Create JSF Library 对话框。使用这个对话框定义 JSF 组件库,这样就可以在项目中包含它。这非常适合添加那些包含几个 JAR 的组件库或依赖于其他项目的 .jar 文件的组件库。
在 Library Name 字段中输入库名(我使用 Spring Framework),然后从 Version Supported 下拉菜单中选择 v1_1,因为 MyFaces 实现了 1.1 版的 JSF 规范。
点击 Add 按钮,然后选择 Spring .jar 文件:spring.jar(见 图 4)。
图 4. 建立 Spring Framework 库引用
这样就行了。Spring Framework 还附带了其他 JAR 文件;spring.jar 包含其中所有内容。如果您希望以更细的粒度控制应用程序的内容,或者希望节省服务器上的空间,那么可以在这些文件中进行选择。Spring 发行版附带的 readme.txt 文件中提供了每个 JAR 文件的依赖项的完整清单。还有另一个文件(spring-mock.jar),其中包含模拟服务器上下文和帮助进行单元测试的其他类:
spring-core.jar —— 核心实用程序;所有代码都需要这个文件
spring-beans.jar —— JavaBeans 支持,bean 容器
spring-aop.jar —— AOP 框架,源代码级元数据支持,AOP Alliance 接口
spring-context.jar —— 应用程序上下文,验证,Java Naming and Directory Interface(JNDI),UI 上下文支持
spring-dao.jar —— Data Access Objects(DAO)支持,事务处理基础设施
spring-jdbc.jar —— JDBC 支持
spring-support.jar —— Java Management Extensions(JMX)支持,J2EE Connector Architecture(JCA)支持,调度支持,邮件支持,缓存支持
spring-web.jar —— Web 应用程序上下文,多部分解析器,Struts 支持,JSF 支持,Web 实用程序
spring-webmvc.jar —— Framework servlet,Web MVC 框架,Web 控制器,Web 视图
spring-remoting.jar —— Remoting 支持,Enterprise JavaBeans(EJB)支持,Java Message Service(JMS)支持
spring-orm.jar —— iBATIS SQL Maps 支持,Apache Object Relational Bridge(OJB)支持,TopLink 支持,JDO 支持
spring-hibernate.jar —— Hibernate 2.1 支持,Hibernate 3.0 和更高版本支持
点击 Finish(见 图 4)将新的 Spring Framework 库添加到项目属性的 JSF Library References 面板中的列表中。这个新的 Spring Framework 库添加到右边的列表中,它会自动地包含在项目的 .war 文件中。
点击 OK 应用修改并关闭项目属性对话框。
任务列表
为了启用 Spring Framework,需要将以下东西添加到应用程序中:
将一个新的 <listener> 添加到 web.xml 中
将一个新的 <variable-resolver> 添加到 faces-config.xml 中
将一个新的托管属性添加到 bean 中;这指定如何将 Spring bean 注入现有的应用程序
applicationContext.xml 文件,它定义应用程序的 bean(包括现有的 JSF bean)
SignupData bean 的一个新属性
一个新的基于 Spring 的 bean
一些表明新的 Spring bean 正在工作的内容
我们开始吧!
添加 <listener>
将 清单 6 中的代码添加到 web.xml 中,放在现有的 <listener> 元素前面,作为 <web-app> 元素的子元素,而不是任何其他 web.xml 标记的子元素。
清单 6. 在 web.xml 中启用 Spring Framework
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener> 元素将 Spring 的 ContextLoaderListener 添加到应用程序中;它启动 Spring 的根 WebApplicationContext,从而处理在启动应用程序时需要的其他 Spring 部分的创建和配置。
添加 Spring 变量解析器
保存 web.xml 文件,并右击 faces-config.xml 文件。
从上下文菜单中选择 Open With > XML Editor,从而编辑这个文件,让应用程序使用 Spring 变量解析器之一。
将 清单 7 中的代码行添加到 faces-config.xml 中的 <application> 元素中。
清单 7. 在 faces-config.xml 文件中指定使用 Spring 变量解析器
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolv
er</variable-resolver>
DelegatingVariableResolver 将查找应用程序使用的任何 bean 名称或 bean 属性引用。如果它无法解析对 Spring bean 或属性的引用,就会将查找委托给标准的 JSF 变量解析器。
将一个新的托管属性添加到 bean 中
要把一个新属性添加到这个文件中声明的 signupData bean 中;hash 属性将由 Spring bean 管理,用来演示将 Spring 注入现有应用程序的技术。
将 清单 8 中的代码添加到 faces-config.xml 中定义 signupData bean 的 <managed-bean> 块里面。
清单 8. 将一个托管属性添加到现有的 bean 中
<managed-property>
<property-name>hash</property-name>
<value>#{genHash.hash}</value>
</managed-property>
这会创建一个新的 hash 托管属性,它映射到稍后定义的 genHash bean 的 hash 属性。
添加 applicationContext.xml 文件
保存 faces-config.xml 文件。
右击 devSignup 项目的 WEB-INF 文件夹,然后从上下文菜单中选择 New > File。
输入 applicationContext.xml 作为文件名,然后将 清单 9 中的代码添加到新文件中。
清单 9. 定义 Spring 管理的 bean
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="signupData" class="devSignup.SignupData"
lazy-init="true"/>
<bean id="genHash" class="devSignup.HashGenerator"
lazy-init="true"/>
</beans>
这些是 Spring 将知道的 bean,所以在这里也会找到 JSF bean,signupData。Spring 的 bean 工厂会在需要时创建和管理这些 bean。如果保持 lazy-init 属性为默认值(false),这些 bean 就会在应用程序启动时创建。如果将 lazy-init 设置为 true,bean 就会在需要它们时创建。
基于 Spring 的 bean
将 清单 10 中的 Java 代码添加到 devSignup 文件夹中的 SignupData.java 中;这会添加 hash 属性及其访问器。
因为这是一个托管属性,它引用另一个 bean 中的一个属性,所以 Spring 在内部使用它引用另一个 bean 中的属性。JSF 应用程序实际上不使用它,因为 Spring 的 DelegatingVariableResolver 会截取对它的任何引用。
清单 10. 将 hash 属性添加到 SignupData.java 中
private String _hash = null;
public SignupData() {
this._birthday = new java.util.Date();
}
public String getHash() {
return this._hash;
}
public void setHash( String newHash ) {
this._hash = newHash;
}
还需要在 devSignup 包中创建一个新的 Java 类,HashGenerator。
右击 devSignup 项目中的 src 文件夹,然后从上下文菜单中选择 New > Other。
在这个向导中,选择 Class,然后点击 Next 创建一个新的 Java 类。
将包设置为 devSignup(或者点击 Package 字段旁边的 Browse 按钮并选择 devSignup),将名称设置为 HashGenerator。
点击 Finish 创建新类,并按照 清单 11 中的代码编辑它的源代码。
清单 11. 新的 HashGenerator 类
package devSignup;
import javax.faces.context.FacesContext;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.jsf.FacesContextUtils;
public class HashGenerator {
public void setHash( String newHash ) {
// Do nothing, this is a read-only bean.
return;
}
public String getHash() {
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(
FacesContext.getCurrentInstance());
try {
SignupData myBean = (SignupData)ctx.getBean("signupData" );
return Integer.toString( myBean.getScreenName().hashCode() );
} catch( NoSuchBeanDefinitionException ex ) {
return "no-data-bean";
} catch( javax.faces.FacesException ex ) {
return "no-screen-name";
}
}
}
这个 HashGenerator bean 有一个只读属性:hash。尝试设置这个属性不会产生任何效果;应该选择将其记入日志,或者利用它来建立更强大的 hash 生成方法。在 getHash() 方法中提供了您看到的第一段 Spring Java 代码。
在 getHash() 方法中,使用 Spring 的 FacesContextUtils.getWebApplicationContext() 方法创建一个 ApplicationContext 对象,然后就可以使用这个对象查找在应用程序中运行的特定 bean 实例。在这里,使用它寻找 signupData bean,以便可以通过 Java String 对象的 hashCode() 方法提供它的 screenName 属性。如果无法找到这个 bean,或者请求了一个无效的属性,就会引发异常,这里的 try/catch 块捕捉并处理这些异常。
这就是所有代码。现在,当构建并部署这个应用程序之后,bean 将在 Spring 中运行,还会运行 Spring 提供的所有其他东西。更复杂的应用程序可以相当轻松地利用这些特性;例如,可以使用 Spring 对 Hibernate(一种对象/关系持久化和查询服务)的支持来存储和检索用户数据,并提供一种将现有用户登录进开发人员论坛的方法。
基于 Spring 的新 bean 的运行效果
应该做的最后一件事是,在应用程序中添加一些东西,以便能够看到这个新的 HashGenerator bean 的运行效果。
在 Eclipse 中打开 signup-success.jsp 文件。您可能还记得,当用户成功地通过注册页面时,就会显示这个页面。修改 <p> 元素中的内容,让它显示用户新的屏幕名以及计算出的 hash 值。
将当前的 <p>...</p> 元素替换为 清单 12 的内容。
清单 12. 显示您的劳动成果
<p>
Your application was successful, ${signupData.screenName}, welcome to our
forums!
Your hash is ${signupData.hash}.
</p>
现在,页面上不再显示一般化的欢迎消息,而是用个性化的消息欢迎用户,他们会看到直接来自 signupData bean 的名称以及来自 signupData 的 hash 属性引用的 HashGenerator bean 的 hash 值。这个页面看起来像 图 5 这样。
图 5. 现在,用一个更加个性化的消息向用户祝贺成功
因为已经修改完 Developer Forum Signup 应用程序,现在需要将它部署到 Geronimo 上。
部署新的 Developer Signup 应用程序
现在,是时候看看 Developer Signup 应用程序的工作效果了。需要构建这个项目、导出 .war 文件并将它部署到 Geronimo 服务器上。
在 Eclipse 的 Navigator 视图中点击 devSignup 项目,然后从菜单中选择 Project > Build Project。Eclipse 编译 Java 代码并验证 JSP 页面和 XML 文件。
在 Navigator 视图中右击 devSignup,然后从上下文菜单中选择 Export。
在 Export 向导中,展开 Web 组,选择 WAR file,然后点击 Next 显示 WAR Export 面板,见 图 6。
图 6. 导出 .war 文件
点击 Browse 按钮,选择一个目标目录和 .war 文件的文件名(我将自己的文件作为 devSignup.war 保存到桌面,这样在服务器上部署它时就很容易找到它。)
点击 Finish,导出 .war 文件。
打开您喜欢的 Web 浏览器,并访问 http://localhost:8080/console/(如果您的 Geronimo 服务器不在同一台机器上运行,那么要用它的主机名替换 localhost)。这会显示 Geronimo 管理控制台登录屏幕。
登录管理控制台(记住,默认用户名是 server,默认密码是 manager,应该修改它们。)
如果在服务器上已经运行着 devSignup(因为您已经按照前面的教程进行了实践),那么点击屏幕左边列表中的 Applications 部分中的 Web App WARs 项。这会列出已经安装的所有 Web 应用程序,每个应用程序旁边有一个 Uninstall 链接。在部署新版本之前应该先卸载 devSignup。
点击 Console Navigation 列表中 Applications 部分中的 Deploy New,显示 Install New Applications 屏幕。
点击 Archive 字段旁边的 Browse 按钮,找到刚才创建的 .war 文件。
因为已经选中了 Start app after install,点击 Install,上传 .war 文件并启动应用程序。在浏览器完成存档文件的上传而且 Geronimo 启动了应用程序之后,会看到一个成功消息。
这样就完成了,您已经用强大的 Spring Framework 成功地扩展了 Developer Signup Web 应用程序!
结束语
本教程简要介绍了 Spring Framework,并讨论了如何将它添加到一个现有的 JSF 应用程序中,即在 第一篇教程 中开始开发的 Developer Forum Signup 示例应用程序。
在这个系列中,您了解了 Apache MyFaces 以及可以用来扩展 JSF Web 应用程序的几种技术和框架,还了解了如何使用 Eclipse IDE 的 Web Tools Platform 简化 JSF 应用程序的开发。我希望这个系列能够对您有所帮助!
本文示例源代码或素材下载
Tags:使用 JavaServer Faces
编辑录入:爽爽 [复制链接] [打 印]赞助商链接