首页 > 代码库 > Struts 笔记
Struts 笔记
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="http://www.mamicode.com/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="http://www.mamicode.com/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中。
Struts 笔记