IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Java technology | Web development | Open source  >

基于 Struts 2 开发 Web 应用

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

吴 春峰, 软件工程师, IBM
程 炜, 软件工程师, IBM

2009 年 9 月 25 日

本文主要介绍在 IBM 产品平台上开发基于 Struts 2 的 Web 应用。Struts 2 与传统的 Struts 1 已经有了本质区别,例如在 Struts 2 中不再需要 ActionForm,任何 Java Bean 都可以用来捕获 form 表单输入参数等。本文将首先介绍如何利用 Rational Software Architect 7(RSA 7)以及 WebSphere Application Server 6.1(WAS 6.1)搭建 Struts 2 开发环境,然后通过一个实例介绍如何开发 Struts 2 应用。

引言

作为 Java Web 应用的典型框架,Struts 一直受到 Java 开发者的青睐,Struts 2 作为 Struts 发展的又一个里程碑,以 WebWork 为基础,提供了更易于使用,功能更强的 MVC 框架。同时它可以帮助开发人员更快速、高效、方便地实现一个 Java Web 应用系统。

对于开发人员来讲,不同的项目可能需要不同的开发和运行 Struts 2 的平台,Struts 2 需要以下环境:Servlet API 2.4, JSP API 2.0, Java 5。IBM WebSphere Application Server 6.1(以下简称 WAS 6.1) 符合 Sturts 2 对运行环境的所有要求。另外,IBM Rational Software Architect 7(以下简称 RSA)提供了设计、开发各种应用的工具,其中包括创建和开发 Web 应用。二者的组合将是开发 Struts 2 的理想平台。





回页首


基于 RSA 及 WAS 搭建 Struts 2 开发平台

首先我们使用 RSA 创建一个动态 Web 项目,我们假设 RSA 中已经创建了一个 WAS 6.1 的服务器:


图 1. 在 RSA 中创建 WAS 6.1 运行环境
图 1. 在 RSA 中创建 WAS 6.1 运行环境

在创建该项目的过程中,需要注意正确设置“目标运行时服务器”以及“动态 Web 模块 版本“, 如下图:


图 2. 设置动态 Web 项目
图 2. 设置动态 Web 项目

其他按默认配置,点击”完成”。创建完项目后,项目的基本包结构会自动生成,为了使该 Web 项目使用 Struts 2 框架,我们需要做一下配置:

配置 Struts 2 类库

本示例使用 Struts 2.1.6 版本 , 所使用的类库可以从 http://apache.etoak.com/struts/library/struts-2.1.6-lib.zip下载,如下图,拷贝相应 jar 包到 Sample/WebContent/WEB-INF/lib 下。注意,本示例只拷贝了一些基本 jar 包,对于需要使用到 Struts 2 复杂功能的应用,需要另外拷贝相应 jar 包。


图 3. 设置 Struts 2 依赖的 Jar 包(查看大图
图 3. 设置 Struts 2 依赖的 Jar 包

配置 web.xml

为了让所有 web 请求通过 struts 2 框架处理,我们需要在 web.xml 中设置相应的 filter 以及 filter mapping, 对于 struts 2.1.6, 应设置成如下图高亮部分:


图 4. 在 web.xml 中设置 filter 和 filter mapping(查看大图
图 4. 在 web.xml 中设置 filter 和 filter mapping

对于 Struts 2 早期版本(2.1.3 之前),一般设置 filter 为 FilterDispatcher,具体如下:

<filter> 
    <filter-name>struts2</filter-name>                 
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>struts2</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Stuts 2 的 taglib 已经自动包含在 struts-core.jar, 服务器会自动找到相应 taglib,所以 web.xml 中不再需要设置 taglib。

配置 Web 容器

当在 WAS 6.1 上运行 struts 2 应用程序时,需要另外设置 web 容器的一个定制属性:

com.ibm.ws.webcontainer.invokefilterscompatibility=true, 否则,所有 Struts 2 Action 不起作用。该设置可以在 WAS 控制台上设置如下:


图 5. 设置 Web 容器(查看大图
图 5. 设置 Web 容器

以上步骤完成了开发 struts 2 应用的准备工作,下面我们开发一个示例。





回页首


示例开发

该示例包括两个页面,第一个是管理员浏览所有系统用户(userList.jsp),第二个是管理员创建一个新用户(user.jsp)。图 6 和图 7 分别是两个示例的应用截图。


图 6 . 浏览系统用户
图 6 . 浏览系统用户

图 7. 点击 “创建”按钮创建新用户
图 7. 点击 “创建”按钮创建新用户

点击“提交”,如果通过校验,则返回到第一个页面,如果校验失败,仍回到当前页面,并提示错误信息。

下面我们开发该应用的各个组件:

创建 Action

创建基类

通过基类实现 SessionAware, ServletRequestAware, ServletResponseAware 接口,可以使用 IOC 方式初始化 session, request 和 response。这种实现可以方便所有子类访问 session, request 和 response。

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionSupport;

public class  BaseAction extends ActionSupport 
	implements SessionAware, ServletRequestAware, ServletResponseAware{
	
	private Map sessionMap;
	private HttpServletRequest request;
    private HttpServletResponse response;
    
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
    
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }
    
    public void setSession(Map map){
    	this.sessionMap=map;
    }
    
    public HttpServletRequest getHttpServletRequest(){
    	return request;
    }
    
    public HttpServletResponse getHttpServletResponse(){
    	return response;
    }
    
    public Map getSession(){
    	return sessionMap;
    }
}
			

创建 , 配置 Action

在该示例中,所有 form 表单提交使用一个 Action 类,该类的不同方法将作为不同表单提交的 Action。在该示例中,execute(), createOrEditUser(), submitUser(), deleteUser() 对应于不同表单对应的 action。


图 8. UserAction 代码
图 8. UserAction 代码

在 Struts 2 应用中,action 的配置文件应该位于类根路径下,一个 Struts 2 应用中可以存在多个 action 配置文件,但这些文件需要在 struts.xml 中引用,本例所有 action 在 struts-user.xml 中定义,struts.xml 引用 struts-user.xml。

在 struts-user.xml 中可以看到不同的类方法被配置成不同的 Action, 如果没有指定方法,那么 struts 2 框架会默认调用 execute(), 例如:”showUserList”

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>		
    <package name="user" extends="struts-default" namespace="/admin">
        ……………
        <!-- user list -->
		<action name="showUserList" class="sample.action.UserAction">	
			<result>/WEB-INF/page/userList.jsp</result>			
		</action>
		
		<!-- add user -->
		<action name="createOrEditUser" 
		    class="sample.action.UserAction" 
			method="createOrEditUser">
			<result>/WEB-INF/page/user.jsp</result>
		</action>
		
		<action name="submitUser" 
		    class="sample.action.UserAction" 
			method="submitUser">	
			<result name="input">/WEB-INF/page/user.jsp</result>
			<result name="userList" type="chain">showUserList</result>
		</action>		
		……………					
	</package>
</struts>
			

在 Struts 2 中,如果一个 Action 需要调用另一个 Action, 可以设置 result 的 type 为 chain, 如前面代码片段中的 <result name="userList"type="chain">showUserList</result>

开发页面

在开发 Struts 2 应用时,不可避免会使用大量的 Struts 2 标签,默认 Struts 2 解释这些标签生成 HTML 代码时会加上一些额外的代码,例如可能把 <tr><td> 自动加上,如果我们选择自己灵活控制代码格式,可以参考本示例在 struts.properties 里设置 struts.ui.theme=simple, struts.properties 同样位于类根路径下:


图 9.Struts 标签及配置文件
图 9.Struts 标签及配置文件

下面我们通过 user.jsp 来展示 Struts 2 框架是如何关联 Jsp, Action 以及表单字段的

<%@ taglib prefix="s2" uri="/struts-tags"%>
........
<s2:form action="submitUser" name="submitUser" namespace="/admin">
        
        <table>
            <tr>
                <td><s2:text name="User.Name"/></td>
                <td><s2:textfield name="user.userName"/></td>
            </tr>
            <tr>
                <td><s2:text name="User.Password"/></td>
                <td><s2:password name="user.password"/></td>
            </tr>
            <tr>
                <td><s2:text name="User.Email"/></td>
                <td><s2:textfield name="user.email"/></td>
            </tr>
            ……………
        </table>
</s2:form>
			

S2:form 标签的 action 属性指定了 form 要提交到的 action, 该 action 名已经在 struts-user.xml 中定义。Namespace 属性和 struts-user.xml 中保持了一致,根据 struts-user.xml 的配置信息,该 form 就会被提交到 UserAction 的 submitUser 方法,但是表单各个字段值是如何被 Action 识别的呢?这是由代表 HTML 各种控件的 Struts 2 标签 name 属性指定的,例如 <s2:textfield name="user.userName"/> 就将该字段的值直接映射到 UserAction 的 user 实例变量的 userName 属性,注意,这里要求 user 对象对应的 User 类必须有一个空的构造函数,另外这里的 user 应该是一个标准的 JavaBean, 所有属性应该有 get,set 方法。

我们看一下表单提交后,action 是如何处理的:

public String submitUser() {
    userService.addUser(user);
    return "userList";
}
			

在调用该方法前,Struts 2 框架已经将所有表单参数自动组装到 user 对象中,所以该方法可以直接访问 user 对象,并对其做相应处理 , 该示例中的 userService 是负责 user 对象的增,删,改操作。

添加完 user 对象,该 action 返回了一个字符串”userList”, 该字符串是 struts-user.xml 中 submitUser action 设置的一个返回结果,该返回结果其实是调用另一个 action 来显示现有 user 列表。

表单校验

Struts 2 提供了很多种校验方式,一种是配置方式,可以用来校验基本数据信息,另一种是编程校验,可以用来校验较为复杂的业务逻辑。

如果是通过配置来校验,需要在 Action 类的同目录下建一个 xml 文件,命名规则是 action 类名 -action 别名 -validation.xml。例如,本示例中:UserAction-submitUser-validation.xml, 当 submitUser action 被调用的时候,会先通过该 xml 配置进行校验。下面代码片段是本示例中配置的校验参数,它指定了对哪些表单字段做哪些校验:

<validators>
	<field name="user.userName">
		<field-validator type="requiredstring">
			<param name="trim">true</param>			
			<message key="User.UserName.Required"/>
		</field-validator>
		<field-validator type="stringlength">
		    <param name="minLength">1</param>
		    <param name="maxLength">20</param>
		    <message key="User.UserName.Length"></message>
	   </field-validator>
	</field>
	
	<field name="user.email">
	  <field-validator type="requiredstring">
	      <message key="User.Email.Required"></message>
	  </field-validator>
	  <field-validator type="email">
	      <message key="User.Email.Format"></message>
	  </field-validator>
	</field>	
	
</validators>
			

Struts 2 定义了一些默认类型,例如 ,email, 可以校验 email 格式,在上例中 user.email 指定了校验表单的 email 字段,type=”requiredstring”表明该字段是必须的,type=”email”表明要检验 email 格式。所有的错误信息可以通过 key 来国际化。

另一种是通过编程校验,在 UserAction 中有一个方法:

public void validateSubmitUser(){
    if (user.getPassword().length() < 6){
        this.addFieldError("user.password", getText("User.Password.Length"));
    }
		
}
			

注意该方法的命名,validate+Action 方法名,也就是说该方法会在调用 submitUser Action 时自动被 Struts 2 框架调用。

国际化

Struts 2 中提供了各种机制对日期格式,数字格式做相应的国际化。例如通过 Action 同目录下的 package.properties, 具体可以参照附件,示例代码。

对于普通文本的国际化,需要做以下步骤:

  1. 设置国际化加载文件路径

    struts.properties 中的 struts.custom.i18n.resources 设置了 struts 2 需要自动加载的国际化文件

  2. 访问国际化资源

    任何继承自 ActionSupport 的 Action 类都可以直接使用 getText 方法根据当前 locale 获取相应键的值

在 JSP 中可以使用 OGNL 表达式 %{getText('key')} 或者 <s2:text name="key"/> 来访问国际化资源。

最后,如果以上方式都不适用,可以使用 com.opensymphony.xwork2.util.LocalizedTextUtil 工具类来访问国际化资源。

3.5 异常处理

一般来说,web 应用都会设置一些统一错误页面,用来显示那些未被 try catch 捕捉到的异常信息,该示例在 struts-user.xml 中加入了这样的配置信息:

<global-results>			
    <result name="Exception">/WEB-INF/page/error.jsp</result>			
</global-results>

<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="Exception"/>
</global-exception-mappings>
			

该配置表示在当前 package 下的所有 action, 一旦有 java.lang.Exception 抛出,并且没有被相应 action 捕获的话,系统将显示错误页面,error.jsp

另外,struts 2 也支持在某个 action 内部定义异常处理,例如:

<action name=”xxx” class=”xxx” method=”xxx”>
    …….
    <exception-mapping exception="java.lang.Exception" result="custom_error"/>
    <result name="custom_error">/WEB-INF/page/common/error.jsp</result>
    …….
</action>
			

在错误页面中可以通过 <s2:property value="%{exception.message}" /> 显示异常信息。





回页首


总结

通过该示例开发,我们对 Struts 2 开发平台以及 Struts 2 框架有了一个基本认识,不过要熟练应用 Struts 2,还需要了解它的各类标签,OGNL 表达式。另外 Struts 2 还提供了一些高级特性,如 Interceptor 机制,IOC 机制。充分利用这些新特性会帮助我们更快,更方便地实现一些 Web 应用。






回页首


下载

描述名字大小下载方法
本文示例代码sample.zip17 KBHTTP
关于下载方法的信息


参考资料



作者简介

吴春峰,软件工程师,在 IBM 中国软件开发中心工作,目前从事 Cloud 开发,对 J2EE、Portal、SOA 有着丰富的经验。


程炜,IBM 软件工程师,在 IBM 中国软件开发中心工作,目前从事 SAP 开发。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款