Struts 概述
随着MVC 模式的广泛使用,催生了MVC 框架的产生。在所有的MVC 框架中,出现最早,应用最广的就是Struts 框架。
Struts 的起源
Struts 是Apache 软件基金组织Jakarta 项目的一个子项目, Struts 的前身是CraigR. McClanahan 编写的JSP Model2 架构。
Struts 在英文中是"支架、支撑"的意思,这表明了Struts 在Web 应用开发中的巨大作用,采用Struts 可以更好地遵循MVC 模式。此外, Struts 提供了一套完备的规范,以基础类库,可以充分利用JSP/Servlet 的优点,减轻程序员的工作量,具有很强的可扩展性。
Struts优点
提高开发效率,减轻了程序员的工作量,降低了重复代码(降低代码冗余),文件不再臃肿。
可以规范软件开发的行为。ActionForm为我们封装请求数据
增加代码的扩展性、移植性
提高代码的可重用性、可读性,无需多个Servlet多个方法
Action转发页面只须配置跳转资源即可,无效全路径、硬编码。降低代码的耦合性
Struts 架构的工作原理
1. Model 部分
Struts 的Model 部分由ActionForm和JavaBean 组成。其中ActionForm用于封装用户请求参数,所有的用户请求参数由系统自动封装成ActionForm 对象:该对象被ActionServlet转发给Action; 然后Action 根据ActionForm里的请求参数处理用户请求。JavaBean 则封装了底层的业务逻辑,包括数据库访问等。在更复杂的应用中,JavaBean所代表的绝非一个简单的JavaBean,可能是EJB 组件或者其他的业务逻辑组件。该Model 对应图3 .4的Model 部分。
2. View 部分
Struts 的View 部分采用JSP 实现。Struts 提供了丰富的标签库,通过这些标签库可以最大限度地减少脚本的使用。这些自定义的标签库可以实现与Model 的有效交互,并增加了显示功能。对应图的JSP 部分。
整个应用由客户端请求驱动,当客户端请求被ActionServlet 拦截时, ActionServlet根据请求决定是否需要调用Model 处理用户请求,当用户请求处理完成后,其处理结果通过JSP 呈现给用户。
3. Controller部分
Struts 的Controller 由两个部分组成。
·系统核心控制器—拦截用户请求ActionServlet 派发请求
·业务逻辑控制器—处理用户请求的Action,处理业务逻辑
其中,系统核心控制器是一个ActionServlet。该控制器由Struts 框架提供,继承HttpServlet类,因此可以配置成一个标准的Servlet。该控制器负责拦截所有Http请求,然后根据用户请求决定是否需要调用业务逻辑控制器,如果需要调用业务逻辑控制器,则将请求转发给Action 处理,否则直接转向请求的JSP 页面。业务逻辑控制器负责处理用户请求,但业务逻辑控制器本身并不具有处理能力,而是调用Model 来完成处理。业务逻辑控制器对应图3 .4中的Action 部分。
下面结合图3.7 对Struts 的工作流程作详细的讲解。
Web 应用都是请求一响应的程序结构。程序是由客户端Client 发出Http 请求开始的,客户端请求被ActionServlet 拦截。在ActionServlet 处,有两种情况:
·要求逻辑控制器处理的请求:
·简单转发的请求。
对于第一种的请求,ActionServlet 需要调用对应的Action。因此ActionServlet 将请求转发到Action ,如果请求还配置了对应的FormBean,则ActionServlet 还负责用请求参数填充ActionForm,此时如果ActionForm还没有创建。ActionServlet会帮我们创建一个可以用的ActionForm,如果ActionForm已经创建就直接给我们用, ActionForm 的实质就是JavaBean,专门用于封装请求参数。并且在次期间,如果ActionForm如果有验证方法,会去执行验证方法,如果验证通过会进入Action中。验证失败,会跳转到Action配置的input资源页面。
此时的Action 将无须从HTTP Request 中获取请求参数,而是从ActionForm 中获得请求参数。Action 获得请求参数后,调用Model 对象由JavaBean 处理用户请求。Action处理完用户请求之后,将处理结果包装成ActionForward,回送给ActionServlet。
由于ActionForward 对象封装了JSP 资源的映射。因此, ActionServlet 知道调用合适的JSP 资源表现给客户端。
对于第二种请求, HTTP 请求无须Action 处理,只是对普通资源的请求,作为超级链接的替代。因为ActionServlet 直接将该请求转发给JSP 资源,既不会填充ActionForm,也无须调用Action 处理。
JSP 页面在表现之前,还需要调用对应的JavaBean,此处的JavaBean 不再是包含业务逻辑的JavaBean,而是封装了处理结果的普通vo (值对象)。JSP 页面根据vo 的值,可能利用JSTL 或者Struts 的标签库来生成HTTP 响应给客户端。总之JSP 应尽量避免使用Java 脚本。
Action配置
path是我们请求访问的路径,如果用struts标签,会默认加上.do的后缀。ActionServlet拦截到*.do的请求后,就进行相应的业务处理,然后派发到path对应的Action;
name是Action对象的ActionForm,ActionForm是封装请求的信息,如表单
attribute和name一样,可以省略,在省略的情况下用name。都是对应ActionForm
type是Action对象对应的文件路径,含包名
scope是ActionForm的作用域,默认request
parameter后带方法名称,即请求所执行的方法
forward是转发后的资源页面
ActionForward配置
name逻辑名称和Action中的mapping.forward参数对应
path对应映射的JSP页面
redirect是否重定向请求
forward有全局和局部的2种,如果当前Action配置的forward资源在当前配置的Action中没有找到,然后回到全局的forward资源中查找。局部优先全局
ActonForm配置
name是form的名称
type是form的包名+文件名
ActionForm还有动态ActionForm、验证ActionForm
国际化I18N(Internationalization)
目的:是适应更多的、更好的用户界面
Java 程序的国际化主要通过如下三个类完成。
java.util. ResourceBundle: 对应用于加载一个资源包。
java.util.Locale: 对应一个特定的国家/区域及语言环境。
java.text.MessageFormat: 用于将消息格式化。
为了实现程序的国际化,必须先提供程序所需要的资源文件。资源文件的内容是和很多key-value 对。其中key 是程序使用的部分,而value 则是程序界面的显示。
资源文件的命名可以有如下三种形式。
baseName _language_country.properties。
baseName _language.properties。
baseNarne.properties 。
其中baseName 是资源文件的基本名,用户可以*定义。而language 和count可都不可随意变化,必须是Java 所支持的语言和国家。
1.国际化支持的语言和国家
事实上, Java 也不可能支持所有国家和语言,如需要获取Java 所支持的语言和国家,可调用Locale 类的getAvailableLocale 方法来获取。该方法返回一个Locale 数组,该数组里包含了Java 所支持的语言和国家。
2. 编写国际化所需的资源
国际化所需的资源文件内容是key-value 对,下面提供了两个资源文件,这两个资源文件很简单,只包含一个key-value 对。
下面是MyResource.properties 的文件的内容:
资源文件的内容: key-value 对。
msg=Hello , {O} Today is {1}.
下面是MyResource_zh_CN.properties 文件的内容:
资源文件的内容: key-value 对
msg=你好. {O} 今天是{l}。
所有资源文件的key 都是相同的,只是value 会随国家和语言的不同而变化。
3.程序从哪里获取资源呢?
在ResourceBundle 加载资源时按如下顺序搜索。
搜索所有国家和语言都匹配的资源文件,例如,对于简体中文的环境,先搜索如下文件:
MyResource_zh_CN.properties
如果没有找到国家和语言都匹配的资源文件,则再搜索语言匹配的文件,即搜索如下文件:
MyResource_zh.properties
如果上面的文件依然无法搜索到,则搜索baseNarne 匹配的文件,即搜索如下文件:
MyResource.properties
4. 使用类文件代替资源文件
Java 也允许使用类文件代替资源文件,即将所有的key-value对存入class 文件,而不是属性文件。
用来代替资源文件的Java 文件必须满足如下条件。
·类的名字必须为baseNarne_language_country,这与属性文件的命名相似。
·该类必须继承ListResourceBundle,并重写getContents 方法,该方法返回Object数组,该数组的每一个项都是key=value 对。
eg:下面的类文件可以代替上面的属性文件:
public class MyResource_zh_CN extends ListResourceBundle {
// 定义资源
private final Object myData[][] = { "msg" , " {0}您好!今天是{l} "};
//重写方法getContents()
public Object[] [] getContents() {
//该方法返回资源的key-value对
return myData;
}
}
如果系统同时存在资源文件及类文件,则系统将以类文件为主,而不会调用资源文件。对于简体中文的Locale, ResourceBundle 搜索资源的顺序是:
(1) baseName zh CN.class 。
(2) baseNarne_zh_CN.properties。
(3) baseNarne zh.class 。
(4) baseNarne_zh.properties。
(5) baseNarne.class。
(6) baseNarne.properties。
当系统按上面的顺序搜索资源文件时,如果前面的文件不存在,则会使用下一个:如果一直找不到对应的文件,系统将抛出异常。
struts加载资源文件
资源文件的加载通过struts-config.xml文件来配置,加载资源文件应从Web 应用的WEB-INF/classes路径开始加载。因此,资源文件必须放在WEB-INF/classes路径或该路径的子路径下。如果直接放在WEB-INF/classes 路径下,在配置资源文件时,直接指定资源文件的baseName 即可。但如果放在子路径下,则必须以包的形式配置。
动态ActionForm
Why?当一个form表单的属性、字段非常多的情况下,需要我们不断的修改、添加ActionForm中的属性,并提供getter、setter方法。虽然这个类比较简单,但是大量重复的getter、setter方法也是比较繁琐的。这个时候struts的动态ActionForm就派上用场了。使用动态ActionForm 的目的是为了减少代码的书写量,但是相对在配置方面要复杂些。
配置动态ActionForm
所有的动态ActionForm 的实现类都必须是org.apache.struts.action.DynaActionForm类,或者是它的子类。使用动态ActionForm 与前面不同的是:因为系统不清楚动态ActionForm 的属性,所以必须在配置文件中配置对应的属性。可以使用form-property 元素来配置动态ActionForm 的属性。
<!一配置动态ActionForm,动态Aciton 必须使用乌rnaActionForm 一〉
<form-bean name="loginForm" type="org.apache.struts.action.DynaActionForm">
<!一配置ActionForm的属性: username-->
<form-property name="username" type="java.lang.String"/>
<! 配置ActionForm的属性: pass-->
<form-property name="pass"type="java.lang.String"/>
</form-bean>
<!-- 配置Action中的path , type , name 属性>
<action path="/login" type="com.hoo.LoginAction" name="loginForm">
<!一配置两个局部Forward-->
<forward name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>
<forward name="input" path="/login.jsp"/>
</action>
从上面的配置文件可看出,动态ActionForm 的配置必须增加form-property 元素,每个属性必须对应一个form-property元素。
form-property元素包含两个属性。
name: 属性的名字,必须与JSP 页面的表单域的名字相同。
type: 属性的类型。
使用动态ActionForm
//必须重写该核心方法,该方法actionForm 将表单的请求参数封装成值对象
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
//将ActionForm强制类型转换为DynaActionForm
DynaActionForm loginForm = (DynaActionForm)form;
//从ActionForm中解析出请求参数: username
String username = (String)loginForm.get("username");
//从ActionForm中解析出请求参数: password
String pass = (String)loginForm.get("pass");
//后面的处理与前一个示例的Action 相同。
…………
}
使用动态ActionForm 时,请求参数必须使用DynaActionForm的getter 方法获取。
DynaActionForm 的getter 方法主要有如下三个。
Object get(java.lang.String name): 根据属性名返回对应的值。
Object get(java.lang.String name, int index): 对于有多个重名表单域的情况, Struts将其当成数组处理,此处根据表面域名和索引获取对应值。
Object get(java.lang.String name, java.lang.String key): 对于使用Map 属性的情况,根据属性名及对应key. 获取对应的值。
Struts 的标签库
Struts 提供了大量的标签库,用于完成表现层的输出。借助于Struts 的标签库,可避免在JSP 中嵌入大量的Java 脚本,从而提高代码的可读性。
Struts 主要提供了如下三个标签库。
A、 html: 用于生成HTML 的基本标签。
B、 bean: 用于完成程序国际化,输出Struts 的ActionForm 的属性值等。
C、 logic: 用于完成循环、选择等流程控制。
使用html 标签库
Struts 为htrnl 的大部分标签提供了对应的htrnl 标签, htrnl 所支持的标签大致有如下。
* base: 表现成一个HTML 的<base>标签。
* button: 表现成一个按钮,该按钮默认没有任何动作。
* cancel: 表现成一个取消按钮。
* checkbox: 表现成一个Checkbox 的输入框。
* error: 用于输出数据校验的出错提示。
* file: 表现成一个文件浏览输入框。
* form: 表现成一个form 域。
* frame: 表现成一个HTML<frame>标签。
* hidde: 表现成一个隐藏域。
* htrnl: 表现成HTML 的<htrnl>标签。
* image: 表现成表单域的image 域。
* img: 表现成一个HTML 的img 标签。
* javascrit: 表现成JavaScript 的校验代码,这些校验代码根据ValidatorPlugIn 生成。
* link: 表现成HTML 的超级链接。
* messages: 用于输出Struts 的各种提示信息,包括校验提示。
* multibox: 表现成一个Checkbox 输入框。
* option: 表现成选择框的一个选项。
* password: 表现成一个密码输入框。
* radio: 表现成一个单选输入框。
* reset: 表现成一个重设按钮。
* rewrite: 表现成一个URL 。
* select: 表现成一个列表选择框。
* submit: 表现成一个提交按钮。
* text: 表现成一个单行文本输入框。
* textarea: 表现成一个多行文本框。
使用bean 标签库
bean 标签库主要用于输出属性值、提示消息及定义请求参数等。下面是bean 标签库的常用标签。
* cookie: 将请求的cookie 的值定义成脚本可以访问的JavaBean 实例。
* define: 将某个bean 的属性值定义成脚本可以访问的变量。
* header: 将请求头的值定义成脚本可以访问的变量。
* include: 将某个JSP 资源完整定义成一个bean 实例。
* message: 用于输出国际化信息。
* page: 将page Context 中的特定项定义成一个bean 。
* parameter: 将请求参数定义成脚本可以访问的变量。
* resource: 加载Web 应用的资源,并将其变成JavaB eano
* struts: 用于将某个Struts 的内部配置成一个bean 。
* write: 用于输出某个bean 的属性值。
使用logic 标签库
logic 标签库是使用最频繁,相对复杂的标签库。logic 标签库主要用于完成基本的流程控制,比如循环及选择等。
logic 标签库主要有如下标签。
* empty: 如果给定的变量为空或者为空字符串,则就计算并输出标签体的内容。
* equal: 如果给定变量与特定的值相等,则会计算并输出该标签体的内容。
* forward: 将某个页面的控制权forward 确定的ActionForward 项。
* greaterEqual: 如果给定变量大于或等于特定的值,则会计算并输出标签体的内容。
* greaterThan: 如果给定变量大于特定的值,则会计算井输出标签体的内容。
* iterate: 通过遍历给定集合的元素,对标签体的内容进行循环。
* lessEqual: 如果给定变量小于或等于特定的值,则会计算并输出标签体的内容。
* lessThan: 如果给定变量小于特定的值,则会计算并输出标签体的内容。
* match: 如果特定字符串是给定消息合适的子字符串,则会计算并输出标签体的内容。
* messagesNotPresent: 如果请求中不包含特定的消息内容,将计算并输出标签体的内容。
* messagesPresent: 如果请求中包含特定的消息内容,则计算并输出标签体的内容。
* notEmpty: 如果给定的变量既不为空,也不是空字符串,则计算并输出标签体的内容。
* notEqual: 如果给定变量不等于特定的值,则会计算并输出标签体的内容。
* notMatch: 如果特定宇符串不是给定消息合适的子字符串,则会计算并输出标签体的内容。
* notPresent: 如果特定的值没有出现在请求中,则计算并输出标签体的内容。
* present: 如果特定的值出现在请求中,则计算并输出标签体的内容。
* redirect: 重定向页面。
Struts 的数据校验
数据校验也称为输入校验,指导对用户的输入进行基本过滤,包括必填宇段,宇段必须为数字及两次输入的密码必须相匹配等。这些是每个MVC 框架都应该完成的任务,Struts 提供了基本的数据校验,如果结合commons-validator, Struts 则拥有强大的校验框架,包括进行客户端的JavaScript 校验等。
Struts 的数据校验大致有如下几种方式:
ActionForm 的代码校验。
Action 里的代码校验。
结合commons-validator.jar 的校验。
ActionForm 的代码校验
ActionForm 的代码校验是最基本的校验方式。这种校验方式是重写ActionForm 的validate 方法,在该方法内对所有的宇段进行基本校验。如果出现不符合要求的输出,则将出错提示封装在ActionError 对象里,最后将多个ActionError 组合成ActionErrors 对象,该对象里封装了全部的出错提示。并将错误信息用<html:error/>展现在配置的input的失败页面上。
Action 的代码校验
在Action 里通过代码完成输入校验,是最基本,也最容易使用的方法。与最初的MVC 设计相似,在调用业务逻辑组件之前,先对数据进行基本校验。这是最传统也是最原始的方法。
这种校验方式非常容易理解,所有的代码都需要程序员自己控制,相当灵活。
但有如下几个不方便之处。
·用户需要书写大量的校验代码,使程序变得烦琐。
· 数据校验应该在填充ActionForm里完成,最好能在客户端完成校验,而不是推迟到Action 里才完成数据校验。
注意:在实际的使用中,这种校验方式不仅程序开发复杂,且性能也不高。
结合commons-validator.jar 的校验
借助于commons-validator.jar 的支持, Struts的校验功能非常强大,几乎不需书写任何代码。不仅可以完成服务器端校验,同时还可完成客户端校验,即弹出Javascript 提示。
使用commons-validator.jar 校验框架时,有如下几个通用配置。
·增加校验资源。
·利用ValidatorPlugIn 加载校验资源。
·ActionForm 使用ValidatorForm 的于类。
下面分别通过三个示例讲解这三种校验:基本的校验、对动态ActionForm 执行校验及弹出JavaScript 校验提示。
1. 继承ValidatorForm 的校验
如果需要使用commons-validator 框架,请按如下步骤进行。
(1) Struts 的ActionForm必须是ValidatorForm的子类,提供验证属性字段的getter、setter方法
(2) 编写表单域时必须满足校验规则。校验规则都由规则文件控制,规则文件有以下两个。
* validator-rules.xml 文件
* validation.xml 文件
第一个文件可在Struts 的解压缩后的文件夹的lib 下找到,将该文件复制到WEB-INF
2. common-validator支持的校验规则
common-validator支持的校验规则非常丰富,特别是mask 和validwhen 两个规则,
极大地丰富了该校验框架的功能。
常用的校验规则有如下几种。
* required: 必填。
* va1idwhen: 必须满足某个有效条件。
* minlength: 输入必须大于最小长度。
* maxlength: 输入必须小于最大长度。
* mask: 输入匹配正确的表达式。
* byte: 输入只能是一个byte 类型变量。
* short: 输入只能是一个short 类型变量。
* integer: 输入只能是一个integer 变量。
* long: 输入只能是一个long 变量。
* float: 输入只能是一个float 变量。
* double: 输入只能是一个double 变量。
* date: 输入必须是一个日期。
* intRange: 输入的数字必须在整数范围内。
* floatRange: 输入的数字必须在单精度浮点数范围内。
* doubleRange: 输入的数字必须在双精度浮点数范围内。
* email: 输入必须是有效的E-mail 地址。
* uri: 输入必须是有效的uri 地址。
3.使用DynaValidatorForm 的校验
即使不书写ActionForm,也可以利用cornmon-validator 校验框架。此时使用的ActionForm 的实现类,必须既是动态Form ,也是验证Form,DynaValidatorForm 就是满足这两个条件的Form。
4. 弹出客户端JavaScript提示
如需要弹出客户端JavaScript 校验非常简单,无须修改其他配置文件,只需修改登录使用的JSP 页面的两个地方。
(1) 为form 元素增加onsubmit="return validateXxxForm(this);"属性,其中的XxxForm就是需要校验的form 名,与struts-config.xrnl中配置的form-bean 的name 属性一致,也与validation.xrnl文件中需要校验的form 的name 属性一致。
(2) 增加<html:javascript formName="xxxForm"/> ,其中xxxForm 是需要校验的form 名。
注意:即使使用了客户端技验规则,也不要删除页面的htm1 :rnessages 标签。因为该标签会在客户端技验通过,而在服务器端技验并未通过时弹出提示。
Struts 的异常框架
Struts 1.1 版本中加入了对异常的处理,称之为Exception Handling,标志着作为一个整体的框架, Struts 越来越趋于成熟。
在以前的Struts 开发过程中,对于异常的处理,主要是采用手动处理的方式:如通过try/catch 等捕获异常:然后将定制个性化的,比较详细的错误信息放进ActionMessage中:最后在返回页面中把这些错误信息反馈给用户。
对于异常的原始信息,不管是最终用户还是开发员都不希望看到。
借助于Struts 的异常框架,异常处理只需通过struts-config.xm1文件定义即可。根据异常定义的位置不同,异常可分为局部异常和全局异常两种。
·局部异常作为action 的子元素中定义。
·全局异常在globa1-excetpions 元素中定义。
异常定义的格式如下:
<exception key="keyNarne" type="ExceptionNarne" scope="scope" path="uri"/>: 当Struts 出现ExceptionNarne 的异常时,页面自动转向uri 指向的资源,并在该页面输出keyName 对应的国际化中的出错提示。
几种常用的Action
除了基本的Action 之外, Struts 还提供了几个其他类型的Action ,这些Action 大大丰富了Struts 的功能。下面介绍如下儿个常用的Action 。
* DispatchAction: 能同时完成多个Action 功能的Action 。
* ForwardActon: 该类用来整合Struts 和其他业务逻辑组件,通常只对请求作有效性检查。
* IncludeAction: 用于引入其他的资源和页面。
* LookupDispatchAction: DispatchAction 的子类,根据按钮的key ,控制转发给action的方法。
* MappingDispatchAction: DispatchAction 的子类,一个action 可映射出多个Action地址。
* SwitchAction: 用于从一个模块转换至另一个模块,如果应用分成多个模块时,就可以使用SwitchAction 完成模块之间的切换。
DispatchAction
在该action 的配置中,增加了parameter属性,该属性用于指定参数名,即Struts 将根据该参数的值调用对应的方法。为了让请求增加method 的参数,method参数对应的是要请求执行的方法。
<action path="/login" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="method">
<forward name="success" path="/welcome.jsp"/>
</action>
Login.do?method=login
MappingDispatchAction
可将同一个Action 的不同方法映射成多个Action URI ,这种Action 的写法与DispatchAction 非常相似,同样不需要重写execute 方法,而是将书写多个自定义的方法。这些方法除了方法名与execute 方法不同外,其他的参数列表及异常处理完全一样。
<!-- 配置第一个Action. 实现类是com.hoo.LoginAction , parameter 为add-->
<action path="/add" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="add">
<forward name="success" path="/welcome.jsp"/>
</action>
<! 配置第二个Action. 实现类是com.hoo.LoginAction , parameter 为modify-->
<action path="/modify" type="com.hoo.LoginAction" name="loginForm" scope="request" validate="true" input="login.jsp" parameter="modify">
<forward name="success" path="/welcome.jsp"/>
</action>
其中,path对应的是请求的地址uri,而parameter是对于当前请求所执行的方法;
注意:使用MappingDispatchAction 并没有带来太大的优势,系统完全可以书写两个Action,分别定义两个不同的action 映射,而其他部分没有区别。
LookupDispatchAction
LookupDispatchAction也是DispatchAction 的一种,但它的处理更加简单。该Action也可包含多个处理方法,它可让处理方法与按钮直接关联,无须使用任何的JavaScript脚本。因此可通过重写getKeyMethodMap方法完成按钮与Action 中方法的关联。
//用于关联按钮和方法
protected Map getKeyMethodMap() {
Map map = new HashMap();
//如果按钮标题的key 为button.add. 则提交该按钮时对应add 方法
map .put ("button. add" , "add");
//如果按钮标题的key 为button.modify. 则提交该按钮时对应modify 方法
map.put ("button.modify" , "modify") ;
return map;
}
ForwardAction
如果需要从一个页面或资源转换到另一个资源时,直接使用页面或资源路径的超级链接定位并不是好的做法,这使得控制器没有机会处理相关的请求事直。
使用ForwardAction可以完成请求的转发,当控制器调用ForwardAction的perform()方法时,它会使用属性parameter 所设定的路径进行forward 的动作。下面是一个设定ForwardAction的例子:
<actlon-mapplngs>
<action path="/welcome" type="org.apache.struts.actions.ForwardAction" parameter="/welcome.jsp"/>
</action-mappings>
该action 仅仅完成转发,并没有执行其他的额外动作。页面控制转发的代码如下:
<a href="welcome.do">转入</a>
当单击转入超级链接时,将可以转向ForwardAction中parameter指向的资源。
IncludeAction
IncludeAction的用法与ForwardAction的用法比较相似,区别在于ForwardAction将跳转到action 定义的资源,而IncludeAction用于引入该action 对应的资源。
下面是IncludeAction定义的源代码:
<action-mapplngs>
<action path="/welcome" type="org.apache. struts.actions.IncludeAction" parameter="/welcome.jsp"/>
</action-mappings>
该action 用于经welcome.jsp 作为资源导入。
页面中负责加载该action 所导入资源的代码如下:
<jsp:include page="welcome.do"/><br>
上面的代码将会把welcome action 定义的资源导入该页面。
SwitchAction
SwitchAction 主要用于模块之间的切换。当一个应用之中存在多个模块时,使用SwitchAction在不同模块之间的action 之间切换还是相当方便的。
Struts 的常见扩展方法
Struts 的强大吸引力还来自于它的可扩展性,其扩展性通常有如下三种方式。
·实现PlugIn: 如果需要在应用启动或关闭时完成某些操作,可以创建自己的PlugIn类。
·继承RequestProcessor: 如果想在请求被处理中的某个时刻做一些业务逻辑时,可以考虑实现自己的RequestProcessor 类。
·继承ActionServlet: 如果需要在每次开始处理请求之前,或者处理请求结束之后完成某些操作,可以实现自己的ActionServlet 来完成扩展。
下面分别从三个方面来介绍Struts 的扩展。
实现PlugIn 接口
Struts 已经演示了PlugIn 的扩展方法:与common- validation 的整合。后面还将介绍Spring 与Struts 的整合,也利用了PlugIn 的扩展。
在下面的应用中,系统使用Hibernate 作为持久层,在启动时创建SessionFactory 实例,并将该SessionFactory 存入application ,在应用关闭时销毁SessionFactory 。只需如下两步即可完成此功能。
(1) 实现自己的PlugIn 类。
实现PlugIn 接口必须实现如下两个方法。
1 void destroy()。
2 void init(ActionServlet serlet, ModuleConfig config) 。
应用启动时调用init 方法,而应用关闭时则调用destroy 方法。
下面是SessionFactoryLoaderPlugIn 的实现类:
public class SessionFactoryLoaderPlugin implements PlugIn {
//Hibernate 的配置文件
private String configFile;
//应用关闭时,销毁资源
public void destroy()
System.out.println("系统销毁SessionFactory");
}
//应用启动时,完成SessionFactory 的初始化
public void init(ActionServlet actionServlet , ModuleConfig config) throws ServletException
System.out.println("系统以" + getConfigFile() + "为配置文件初始化SessionFactory") ;
//获取Plugln 配置文件的方法
public String getConfigFile() {
return configFile;
}
// 负责加载Plugln 配置属性的方法
public void setConfigFile(String configFile) {
this.configFile = configFile;
}
}
在上面的PlugIn 中,并没有真正初始化SessionFactory ,仅在控制台打印出字符串来标识创建动作。另外,还提供了configFile 属性的setter 和getter 方法,这两个方法负责访问plugin 元素的configFile 属性。
( 2 ) 将SessionFactoryLoaderPlugIn 配置在struts-config.xml 文件中。方法与ValidatorPlugIn 的配置并没有区别,下面是配置SessionFactoryLoaderPlugIn 的代码:
<plug-in className="hoo.SessionFactoryLoaderPluging">
<set-property property="conf工gFile" value=" WEB-INF/hibernate.cfg.xml"I>
</plug-in>
在配置SessionFactoryLoaderPlugIn 时,配置了configFile 属性,该属性用于确定Hibernate 配置文件的文件名。
继承RequestProcessor
RequestProcessor 是Struts 的核心类,而Struts 的核心控制器是ActionServlet 。但ActionServlet 并未完成真正的处理,只是调用RequestProcessor , RequestProcessor 才是Struts 的核心类。
扩展RequestProcessor 的实例在Spring 中有个示范, Spring 提供的Delegating RequestProcessor 是一个很好的示例。下面示例对RequestProcessor 进行简单的扩展。
RequestProcessor 包含了如下常见的方法。
* ActionForm processActionForm: RequestProcessor填充ActionForm 时执行该方法。
* Action processActionCreate: RequestProcessor 调用Action 时调用该方法。
* boolean processPreprocess: 预处理用户请求时执行该方法。
* boolean processValidate: 处理输入校验时调用该方法。
扩展RequestProcessor 只需两步即可。
(2)在struts-config.xml 文件中配置MyRequestProcessor。用户重写了RequestProcessor,但Struts 并不知道,必须在struts-config且nl 中配置才可以。
下面是配置MyRequestProcessor 的代码:
<controller processorClass="lee.MyRequestProcessor" />
该属性的配置应该放在action-mappings元素之后。
注意:重写RequestProccessor的方法时,别忘了使用super 来调用父类的动作。如果没有调用该方法,意味着开发者必须完成Struts 框架所完成的动作。这是不应该的,因为程序员只是在框架中加入额外的处理,并不是要替代Struts。
继承ActionServlet
如果需要在开始处理请求,或者处理结束之后加入自己的处理时,可对ActionServlet进行扩展。例如解决中文的编码问题。
ActionServlet 接收处理请求参数时,并不是按GBK 的解码方式处理请求,因此容易形成乱码。为了解决该问题,可以强制指定ActionServlet 使用GBK 的解码方式。
继承ActionServlet重写process方法,设置request、response编码为gbk,然后配置在web.xml中。