为Struts应用配置 web.xml 文件
(1) 在web.xml中配置 Struts 的 ActionServlet
<servlet> <servlet-name> action </servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <init-param> <param-name> config </param-name> <param-value> /WEB-INF/struts-config.xml </param-value> </init-param> <init-param> <param-name> debug </param-name> <param-value> 3 </param-value> </init-param> <init-param> <param-name> detail </param-name> <param-value> 3 </param-value> </init-param> <load-on-startup> 0 </load-on-startup> </servlet> <servlet-mapping> <servlet-name> action </servlet-name> <url-pattern> *.do </url-pattern> </servlet-mapping>
注意的一点:不管应用中包含多少个子应用,都只需要配置一个 ActionServlet, 有些开发者希望设置多个 ActionServlet 类来处理应用中的不同功能, 其实这是不必要的,因为 Servlet 本身支持多线程。 而且,目前的Struts框架只允许在应用中配置一个ActionServlet。
(2) 配置欢迎文件清单
<welcome-file-list> <welcome-file>welcome.jsp</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list>
如果<welcome-file-list>元素中指定的所有文件都不存在,服务器将向客户端返回“HTTP 404 Not Found”的出错信息。
由于在<welcome-file-list>元素中不能配置Servlet映射,因此不能直接把Struts的Action作为欢迎文件。但可以采用一种变通的方法来实现。
首先在Struts配置文件中为被调用的Action创建一个全局的 (global) 转发项,例如:
<global-forwards> <forward name="welcome" path="HelloWorld.do"/> </global-forwards>
然后创建一个名为 welcome.jsp 的 JSP 文件 (也可以采用其他文件名称),当该页面被加载时,它把请求转发给以上<forward>元素指定的 Action。welcome.jsp 的代码如下:
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> <html> <body> <logic:forward name="welcome"/> </body> </html>
最后在web.xml文件中把welcome.jsp文件配置为欢迎文件,代码如下:
<welcome-file-list> <welcome-file>welcome.jsp</welcome-file> </welcome-file-list>
(3) 配置错误处理
Struts框架自身有功能强大的错误处理机制,但不能保证处理所有的错误或异常。当错误发生时,如果Struts不能处理这种错误,就把错误抛给Web容器。在默认情况下,Web容器会向用户浏览器直接返回原始的错误信息。如果想避免直接让用户看到原始的错误信息,可以在Web应用的发布描述符中配置 <error-page> 元素,以下代码使用 <error-page> 元素来避免让用户直接看到 HTTP 404 和 HTTP 500 错误。
也可以为 Web 容器捕获的 Java 异常配置 <error-page> 元素,这时需要设置 <exception-type> 子元素,它用于指定 Java 异常类。Web 容器可能捕获如下异常类:
在<exception-type>元素中声明的 Java 异常类必须是以上所列举的情况之一。以下代码演示了如何配置 ServletException 异常和 IOException:
配置 Struts 标签库
Struts框架提供了一些实用的客户化标签库,要使用他们,需要在web.xml中配置它们。
Struts 配置文件
(1)org.apache.struts.config 包
在 Struts 1.1 中加入了 org.apache.struts.config 包。在 Struts 应用启动时,会把 Struts 配置文件中的配置信息读入到内存中,并把它们存放在 config 包中相关 JavaBean 类的实例中,下图为 org.apache.struts.config 包中主要的类框图。
/** * <p>Commons Logging instance. </p> */ protected static Log log = LogFactory.getLog(ModuleConfigImpl.class); // ----------------------------------------------------- Instance Variables // Instance Variables at end to make comparing Interface and implementation easier. /** * <p>The set of action configurations for this module, if any, keyed by * the <code>path</code> property.</p> */ protected HashMap actionConfigs = null; /** * <p>The set of action configuration for this module, if any, keyed by * the <code>actionId</code> property.</p> */ protected HashMap actionConfigIds = null; /** * <p>The set of action configurations for this module, if any, listed in * the order in which they are added.</p> */ protected List actionConfigList = null; /** * <p>The set of exception handling configurations for this module, if * any, keyed by the <code>type</code> property.</p> */ protected HashMap exceptions = null; /** * <p>The set of form bean configurations for this module, if any, keyed * by the <code>name</code> property.</p> */ protected HashMap formBeans = null; /** * <p>The set of global forward configurations for this module, if any, * keyed by the <code>name</code> property.</p> */ protected HashMap forwards = null; /** * <p>The set of message resources configurations for this module, if any, * keyed by the <code>key</code> property.</p> */ protected HashMap messageResources = null; /** * <p>The set of configured plug-in Actions for this module, if any, in * the order they were declared and configured.</p> */ protected ArrayList plugIns = null; /** * <p>The controller configuration object for this module.</p> */ protected ControllerConfig controllerConfig = null; /** * <p>The prefix of the context-relative portion of the request URI, used * to select this configuration versus others supported by the controller * servlet. A configuration with a prefix of a zero-length String is the * default configuration for this web module.</p> */ protected String prefix = null; /** * <p>The default class name to be used when creating action form bean * instances.</p> */ protected String actionFormBeanClass = "org.apache.struts.action.ActionFormBean"; /** * The default class name to be used when creating action mapping * instances. */ protected String actionMappingClass = "org.apache.struts.action.ActionMapping"; /** * The default class name to be used when creating action forward * instances. */ protected String actionForwardClass = "org.apache.struts.action.ActionForward"; /** * <p>Matches action config paths against compiled wildcard patterns</p> */ protected ActionConfigMatcher matcher = null;
上图中的 org.apache.struts.config.ConfigRuleSet 类的功能不同于其他类, 它包含了解析 Struts 配置文件所需要的一组规则。在应用启动时,该类负责构造 org.apache.struts.conifg 包中其他用于保存配置信息的 JavaBean 类的实例。
(2) <Struts-config> 元素
<Struts-config> 元素是 Struts 配置文件的根元素,和它对应的配置类为 org.apache.struts.config.ModuleConfig 类。 <struts-config>元素一个有8个子元素, 它的DTD如下:
(3) <form-beans> 元素
<form-beans> 元素用来配置多个 ActionForm Bean。<form-beans>元素包含零个或多个<form-bean>子元素。每个<form-bean>元素又包含多个属性。
如果想配置动态 ActionForm Bean, 还必须配置 <form-bean> 元素的 <form-property> 子元素, <form-property> 有四个属性
属性 | 描述 |
className | 指定和<form-property>元素对应的配置类,默认值为 org.apache.struts.config.FormPropertyCongig |
initial | 以字符串的形式设置表单字段的初始值。如果没有设置该属性,则基本类型的表单字段的默认值为0,对象类型的表单字段的默认值为 null |
name | 指定表单字段的名字。该属性是必须的 |
type | 指定表单字段的类型。如果表单字段为 Java 类,必须给出完整的类名。该属性是必须的 |
Struts 框架的 DynaActionForm 类及其子类实现了动态 ActionForm, DynaActionForm类是 ActionForm 类的子类。
动态 ActionForm 支持在 Struts 配置文件中完成 ActionForm 的全部配置,没有必要编写额外的程序来创建具体的 ActionForm 类。 配置动态 ActionForm 的方法为: 在 Struts 配置文件中配置一个 <form-bean> 元素,将 type 属性设置成 DynaActionForm 或它的某个子类的全名。以下代码配置了一个名为loginForm 的动态 ActionForm,它包含三个属性:username,password和rememberMe。
<form -bean> 的 <form-property> 子元素用来设置动态 ActionForm 的属性。 <form-property> 元素的 name 属性指定属性名,type 指定属性类型。可以把动态 ActionForm 的属性设为以下 Java 类型:
如果表单字段的值为 Java 基本类型,在配置时应该用相应的包装类型代替,例如 int 类型的包装类型为 Integer:
<form-property initial="0" name="age" type="java.lang.Integer"/>
动态 ActionForm 的 reset() 方法
DynaActionForm 基类提供了 initialize() 方法,它把表单的所有属性恢复为默认值。表单属性默认值由 <form-bean> 的 <form-property> 子元素的 initial 属性决定。 如果没有设置 initial 属性,则表单属性的默认值由其 Java 类型自动决定,例如对象类型的默认值为null,整数类型的默认值为 0.boolean 类型的默认值为 false。
DynaActionForm 基类的 initialize() 方法的代码如下:
// ----------------------------------------------------- ActionForm Methods /** * <p>Initialize all bean properties to their initial values, as specified * in the {@link FormPropertyConfig} elements associated with the * definition of this <code>DynaActionForm</code>.</p> * * @param mapping The mapping used to select this instance */ public void initialize(ActionMapping mapping) { String name = mapping.getName(); if (name == null) { return; } FormBeanConfig config = mapping.getModuleConfig().findFormBeanConfig(name); if (config == null) { return; } initialize(config); }
DynaActionForm 基类的 reset() 方法不执行任何操作,其代码如下:
public void reset(ActionMapping mapping, HttpServletRequest request) { // Default implementation does nothing }
如果希望 Struts 框架在每次把表单数据组装到动态 ActionForm 中之前,先把所有的属性恢复为默认值,可以定义一个扩展DynaActionForm类的子类,然后覆盖起 reset() 方法,在 reset() 方法中只要调用 initialize() 方法即可。
访问动态 ActionForm
Acton类和JSP都可以访问动态 ActionForm,使用方法与标准 ActionForm 大致相同,只有一点小差别。如果使用标准 ActionForm 对象, 在标准 ActionForm 中针对每个属性都提供了 get/set 方法,而 DynaActionForm 把所有的属性保存在一个 Map 类对象中,并提供了下面的用于访问所有属性的通用方法:
public Object get(String name) public void set(String name, Object value)
get(String name) 方法根据指定的属性名返回属性值; set(String name, Object value) 方法用于为给定的属性赋值。 例如,如果要访问 DynaActionForm 类中的 email 属性,可以采用以下代码:
// get email String email = (String) form.get("email"); // set email form.set("email", "[email protected]");
DynaActionForm 的示例 见 附件 “DynamicFormBean.rar”
(3) <global-exceptions> 元素
<global-exceptions>元素用于配置异常处理。<global-exceptions> 元素可以包含零个或者多个<exception>元素。
<exception> 元素用来设置 Java 异常和异常处理类 org.apache.struts.action.ExceptionHandler 之间的映射。
以下是配置<global-exception>元素的示例:
<global-exceptions> <exception key="global.error.invalidlogin" path="/security/signin.jsp" scope="request" type="netstore.framework.exception.exceptions.InvalidLoginException"/> </global-exceptions>
(4) <global-forwards> 元素
<global-forwards>元素用来声明全局的转发关系。 <global-forwards>元素有零个或多个<forward>元素组成。<forward> 元素用于吧一个逻辑名映射到特定的 URL
如下配置<global-forward>元素:
<global-forwards> <forward name="forward1" path="/Action1.do"/> <forward name="forward2" path="/JSP2.jsp"/> <forward name="forward3" path="/JSP3.jsp"/> </global-forwards>
如 JSP1.jsp 把请求转发给 Action1,可以使用以下代码:
<html:link forward="forward1">
或者
<logic:forward name="forward1"/>
如果 Action1 的 execute() 方法把请求转发给 JSP2.jsp,可以使用以下代码:
return (mapping.findForward("forward2"));
(5) <action-mappings> 元素
<action-mappings>元素包含零个或者多个<action>元素。
在 <action> 元素中可以包含多个<exception>和<forward>子元素,它们分别配置局部的异常处理及请求转发仅被当前的 Action 所访问。
在<global-exceptions>元素中定义的<exception>子元素代表全局的异常配置。在<global-forwards>元素中定义的<forward>子元素代表全局的请求转发。在不同位置配置<exception>和<forward>元素的语法和属性是一样的。下图对 Action元素的属性做了描述。
<action>元素的 forward、include 和 type 属性相互排斥,也就是说只能设置其中的一项。forward 属性的作用和 org.apache.struts.actions.ForwardActon 类相同,include 属性的作用和 org.apache.struts.actions.IncludeAction 类相同。
(6)局部的和全局的 <forward> 元素
在 <action> 元素中定义的 <forward> 元素表示局部的请求转发项,在 <globals-forward> 元素中定义的 <forward> 元素表示全局的请求转发项。在两个不同位置定义的 <forward> 元素的语法是一样的。例如下面的两个<forward> 元素的 name 属性都是 "success":
<global-forwards> <forward name="success" path="/success.jsp"/> </global-forwards> <action path="/Action1" ……> <forward name="success" path="/login.jsp"/> </action> <action path="/Action2" ……></action>
假定在 Action1 和 Action2 的 execute() 方法中都执行以下代码:
return (mapping.findForward("success"));
Action1 将把请求转发给局部 <forward> 元素指定的 login.jsp,而 Action2 将把请求转发给全局的 <forward> 元素指定的 success.jsp。 由此可见, 局部 <forward> 元素的优先级高于全局 <forward> 元素的优先级。
(7) <action> 的 forward 属性
<action> 的 forward 属性和 <forward> 子元素是两个不同的概念。forward 属性指定和 path 属性匹配的请求转发路径,例如:
<action path="/hello" forward="/hello.jsp"></action>
对于以上代码,当用户请求的 URI 为 “、heilo.do”,Struts框架将把请求转发给 hello.jsp 文件。
(8) <controller> 元素
<controller> 元素用于配置 ActionServlet。
属性 | 描述 |
bufferSize | 指定上载文件的输入缓冲的大小。该属性为可选项,默认值为 4096 |
className | 指定和 <controller> 元素对应的配置类。默认值为 org.apache.struts.config.ControllerConfig |
contentType | 指定响应结果的内容类型和字符编码。该属性为可选项,默认值为 text/html。如果在 Action 和 JSP网页中也设置了内容类型和字符编码,将会覆盖该设置 |
local | 指定是否把 Local 对象保存到当前用户的 Session 中。默认值为 false |
processorClass | 指定负责处理请求的Java类的完整类名。默认值为 org.apache.struts.action.RequestProcessor。 如果把此项设置为自定义的类,那么应该保证该类扩展了 org.apache.struts.action.RequestProcessor 类 |
tempDir | 指定处理文件上载的临时工作目录。如果此项没有设置,将采用 Servlet 容器为 Web 应用分配的临时工作目录 |
nochache | 如果为 true,在响应结果中将加入特定的头参数:Pragma,Cache-Control 和 Expires,防止页面被储存在客户浏览器的缓存中。默认值为 false |
如果应用包含多个字应用,可以在每个子应用的Struts配置文件中配置<controller>元素。这样,尽管这些子应用共享同一个 ActionServlet 对象,但是他们可以使用不同的 RequestProcessor 类。以下是示例代码:
<controller> <set-property property = "processorClass" value = "org.springframework.web.struts.DelegatingRequestProcessor" /> </controller>
顺便说一下:《spring2.0与struts1.x 整合三种方法》
1. Struts
Struts 是应用最广的Java Web 开发框架, 主要是因为它是最先发行的几个框架之一(2001年6月). 这个框架由 Craig McClanahan 开发完成,现在作为 Apache 软件基金会的一个开源项目。 当时,它极大地简化了 JSP/Servlet 编程范例并且赢得了 大多数正在使用私人框架的开发人员的亲睐。它简化了编程模型,它是开源的,它具有一个庞大的社区,这些都使得这个项目快速成长,同时变得越来越流行。
要将 Struts 与 Spring 集成,你有两个选择:
一: 配置 Spring 将 Action 作为 bean 托管,使用 ContextLoaderPlugin, 并且在 Spring context中设置依赖关系。
二: 继承 Spring 的 ActionSupport 类并且 使用getWebApplicationContext() 方法获取 Spring 管理的 bean。
1.1. ContextLoaderPlugin
ContextLoaderPlugin 是 Struts 1.1+ 的插件,用来为 Struts 的 ActionServlet 加载 Spring context文件。 这个context引用 WebApplicationContext (由 ContextLoaderListener 加载) 作为它的父类。默认的context文件是映射的 Servlet 的名字,加上 -servlet.xml后缀。 如果 ActionServlet 在 web.xml 里面的定义是 <servlet-name>action</servlet-name>, 那么默认的文件就是 /WEB-INF/action-servlet.xml。
要配置这个插件,请把下面的 XML 贴到 struts-config.xml 文件中 plug-ins 部分的底端:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/>
context配置文件的位置可以通过 contextConfigLocation属性来自定义。
< plug-in className = "org.springframework.web.struts.ContextLoaderPlugIn" > <set-property property = "contextConfigLocation" value = "/WEB-INF/action-servlet.xml.xml,/WEB-INF/applicationContext.xml" /> </ plug-in >
你也可以使用这个插件加载所有的配置文件,这在使用测试工具(例如 StrutsTestCase)的时候特别有用。 StrutsTestCase 的 MockStrutsTestCase 不会在启动的时候初始化 Listener,将你所有的配置文件放在plug-in里面是一种解决方案。(有个 已记录的 bug 就是针对这个问题的,但是已经被标记为“无须改正”)。
在 struts-config.xml 中配置好插件以后,你可以配置Sping来管理 Action。Spring (1.1.3以后的版本) 提供下面两种方式:
一:用 Spring 的DelegatingRequestProcessor重载 Struts 默认的 RequestProcessor 。
二:将 <action-mapping> 的 type 属性设为 DelegatingActionProxy。
这两种方法都允许你在 action-context.xml 文件中管理你的 Action 以及依赖关系。 连接 struts-config.xml 和 action-servlet.xml 中的 Action 的桥梁 是 action-mapping 的“path”和 bean 的“name”。如果你在 struts-config.xml 文件中有如下配置:
<action path="/users" .../>
你必须在 action-servlet.xml 中将 Action bean 的名字定义为 “/users”:
<bean name="/users" .../>
1.1.1. DelegatingRequestProcessor
为了在 struts-config.xml 文件中配置 DelegatingRequestProcessor,你需要重载 <controller> 元素的 “processorClass” 属性。 下面的几行应该放在 <action-mapping> 元素的后面。
< controller > < set-property property = "processorClass" value = "org.springframework.web.struts.DelegatingRequestProcessor" /> </ controller >
增加这些设置之后,不管你查询任何类型的 Action,Sping都自动在它的context配置文件中寻找。 实际上,你甚至不需要指定类型。下面两个代码片断都可以工作:
<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>
如果你使用 Struts 的 modules 特性,你的 bean 命名必须含有 module 的前缀。 举个例子,如果一个 Action 的定义为 <action path="/user"/>,而且它的 module 前缀为“admin”,那么它应该对应名为 <bean name="/admin/user"/> 的 bean。
Note
如果你在 Struts 应用中使用了 Tiles,你需要配置 <controller> 为 DelegatingTilesRequestProcessor。
1.1.2. DelegatingActionProxy
如果你有一个自定义的 RequestProcessor 并且不能够使用 DelegatingRequestProcessor 或者 DelegatingTilesRequestProcessor,你可以使用 DelegatingActionProxy 作为你 action-mapping 中的类型。
<action path="/user" type="org.springframework.web.struts.DelegatingActionProxy" name="userForm" scope="request" validate="false" parameter="method"> <forward name="list" path="/userList.jsp"/> <forward name="edit" path="/userForm.jsp"/> </action>
action-servlet.xml 文件中的bean定义依然不变,不管你使用了自定义的 RequestProcessor 还是 DelegatingActionProxy。
如果你把 Action 定义在Spring的context文件里,那么 Spring bean 容器的所有特性都可用了:比如,依赖注入,再比如,为每个请求初始化一个新的 Action 实例。 如果要使用这个特性, Action bean 定义中需要声明scope="prototype"。
如果你把 Action 定义在Spring的context文件里,那么 Spring bean 容器的所有特性都可用了:比如,依赖注入,再比如,为每个请求初始化一个新的 Action 实例。 如果要使用这个特性, Action bean 定义中需要声明scope="prototype"。
1.2. ActionSupport 类
正如前面提到的,你可以使用 WebApplicationContextUtils 类从 ServletContext 中获得 WebApplicationContext 。 另一个简单的办法是继承 Spring 的 Action 类。举个例子,除了继承 Struts 的 Action 之外,你也可以继承 Spring 的 ActionSupport 类。
ActionSupport 类提供了一些便利的方法,例如 getWebApplicationContext()。 下面的例子展示了如何在 Action 中使用它:
public class UserAction extends DispatchActionSupport { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { if (log.isDebugEnabled()) { log.debug("entering 'delete' method..."); } WebApplicationContext ctx = getWebApplicationContext(); UserManager mgr = (UserManager) ctx.getBean("userManager"); // talk to manager for business logic return mapping.findForward("success"); } }
Spring 包含了所有标准 Struts Action 的子类 - Spring 版本在类名末尾附加了 Support:
ActionSupport,
DispatchActionSupport ,
LookupDispatchActionSupport
MappingDispatchActionSupport
你应该选择最适合你项目的集成方式。继承使得你的代码更可靠,并且你确切地知道依赖关系是如何被解析的。 另一方面,使用 ContextLoaderPlugin 允许你方便地在context XML 文件里面增加新的 依赖关系。这两种集成方法,不管哪一种 Spring 都提供了相当好用的选项。
(9) <message-resources> 元素
<message-resources> 元素用来配置 Resource Bundle,Resource Bundle 用于存放本地化消息文本。
属性 | 描述 |
className | 和<message-resources>元素对应的配置类。默认值为 org.apache.struts.config.MessageResourcesConfig |
factory | 指定消息资源的工厂类。默认值为 org.apache.struts.util.PropertyMessageResourcesFactory 类 |
key | 指定 Resource Bundle 存放在 ServletContext 对象中时采用的属性 key。默认值为由Global.MESSAGES_KEY 定义的字符串常量。只允许有一个 Resource Bundle 采用默认的属性 key |
null | 指定 MessageResources 类如何处理未知的消息 key。如果此项为 true,将返回空字符串,如果此项为 false,将返回类似 "???global.label.missing???" 的字符串。该属性为可选项,默认值为true |
parameter | 指定 Resource Bundle 的消息资源文件名。 |
(10)<plug-in> 元素
属性 | 描述 |
className | 指定 Struts 插件类。插件类必须实现 org.apache.struts.action.PlugIn 接口 |
<plus-in> 元素可以包含零个或多个 <set-property> 子元素。<plug-in> 元素的配置实例如下:
<plug-in className="com.greatchn.finance.struts.plugin.SystemInitPlugin"> </plug-in>
(11) 配置多应用模块
同一个应用包含多个子应用,每个子应用可以处理相关的一组功能。
所有的子应用都共享同一个 ActionServlet 实例,但每个子应用都有单独的配置文件。把应用划分为多个子应用模块包括以下步骤:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <init-param> <param-name>config/moduleOne</param-name> <param-value>/WEB-INF/moduleOne/struts-moduleOne.xml</param-value> </init-param> <init-param> <param-name>config/moduleTwo</param-name> <param-value>/WEB-INF/moduleTwo/struts-moduleTwo.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>3</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>3</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>