引用
默认的的拦截器栈被设计成能满足大部分应用的需要,所以不再需要添加新的拦截器或更改拦截器栈。
不同的action可能有不同的关注点, 一些action需要表单验证,一些action需要文件上传功能,一些action需要防止双重提交……struts框架使用“Interceptor”策略使得解决这些关注点变得容易。
理解拦截器
在action执行前后interceptor都要被执行。框架的大部分核心功能(包括类型转化,防止双重提交等……)都是借助拦截器来实现的。 所有的拦截器都是插件式的,你可以为你的action精确的设置需要的拦截器。
action生命周期
配置拦截器
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="timer" class=".."/>
<interceptor name="logger" class=".."/>
</interceptors>
<action name="login"
class="tutorial.Login">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<result name="input">login.jsp</result>
<result name="success"
type="redirect-action">/secure/home</result>
</action>
</package>
拦截器栈
在大部分web程序中,我们发现需要屡次使用相同的拦截器序列。 此时, 我们可以把这些拦截器序列绑定为一个拦截器栈,而无需重申这些拦截器列表。
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="timer" class=".."/>
<interceptor name="logger" class=".."/>
<interceptor-stack name="myStack">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
</interceptor-stack>
</interceptors>
<action name="login"
class="tutuorial.Login">
<interceptor-ref name="myStack"/>
<result name="input">login.jsp</result>
<result name="success"
type="redirect-action">/secure/home</result>
</action>
</package>
几个重要的拦截器
在struts配置文件中,拦截器类被定义为键值对的形式。
拦截器的名字在 struts-default.xml中都进行了定义,如果你继承了 struts-default.xml包,后面的操作你可以通过引用来使用拦截器;如果没有继承struts-default.xml,你需要在<interceptors>中指定名字和名字对应的拦截器类来引用拦截器。
- chain : 使上一个action的属性能在当前的action中有效
- execAndWait : 生成一个新的线程以执行action, 然后返回wait作为result code。而wait这个code可以映射至一张包含刷新指示的页面,告知浏览器每隔数秒自动刷新。当新线程执行action完毕之后,下一个来自浏览器到请求将返回原始action调用所生成的result。
- exception : 映射一个异常页面。 一般情况下,应该为最后一个拦截器。
- fileUpload : 处理文件上传。
- logger : 记录用于追踪的信息(可位于拦截器序列的不同位置)。
- params:使用request参数设置action的属性。request参数会被映射到action中与之同名的属性。
- static-params :将配置文件中参数设置到action实例中。
- prepare : 此拦截器将调用实现了Preparable的action中的prepare方法。
- token : 检查表单中的合法令牌,当表单被多次提交时,跳转到一个错误页面。
- tokenSession :类似于token, 只是不跳转到错误页面,再次生成与第一次相同的页面。
- validation : 调用校验框架读取*-validation.xml文件并且应用在这些文件中声明的校验。
- workflow :为action定义默认的工作流, 一般跟在validation等其它拦截器后。
- timer : 计算ActionInvocation余下部分执行的时间并记录下来。
从2.0.7版本后拦截器和Result中含有的连字符号都被转化为来骆驼格式。
如:(model-driven 被转化为modelDriven)。
直到Struts 2.1.0, 原有的连字符号格式以别名的形式仍被使用。
方法过滤 覆写拦截器参数
一个抽象的过滤器被用于过滤方法的名字。
excludeMethods : 不被包含的方法的名字。
includeMethods : 包含的方法的名字。
如果方法的名字在excludeMethods和includeMethods都适合, 那么将包含方法的名字, includeMethods比excludeMethods的
优先级高。
方法1
<action name="myAction" class="myActionClass">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">myValidationExcudeMethod</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
</action>
方法2
<action name="myAction" class="myActionClass">
<interceptor-ref name="defaultStack">
<param name="validation.excludeMethods">myValidationExcludeMethod</param>
<param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
</action>
拦截器的执行顺序
拦截器提供了一种对处理前后进行包装的思想, 这种观念大大减少了代码副本。(参考AOP)
<interceptor-stack name="xaStack">
<interceptor-ref name="thisWillRunFirstInterceptor"/>
<interceptor-ref name="thisWillRunNextInterceptor"/>
<interceptor-ref name="followedByThisInterceptor"/>
<interceptor-ref name="thisWillRunLastInterceptor"/>
</interceptor-stack>
一些拦截器有可能会打断执行流程,因此拦截器的顺序也是很重要的 。
另, 实现了com.opensymphony.xwork2.interceptor.PreResultListener 的拦截器将在Action执行之后和Result返回之前调用。
thisWillRunFirstInterceptor
thisWillRunNextInterceptor
followedByThisInterceptor
thisWillRunLastInterceptor
MyAction1
MyAction2 (chain)
MyPreResultListener
MyResult (result)
thisWillRunLastInterceptor
followedByThisInterceptor
thisWillRunNextInterceptor
thisWillRunFirstInterceptor
自定义拦截器
自定义拦截器必须实现 com.opensymphony.xwork2.interceptor.Interceptor
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
在拦截器被实例化之后和 intercept方法被调用之前 执行init方法。 此方法用来初始化拦截器需要的资源。
拦截器的主体代码写在intercept中, 和action类似, intercept返回一个result, result被struts2用于将请求转发到另一个资源,调用ActionInvocation 中的invoke 方法以执行action (如果是最后一个拦截器)或调用另一个拦截器。
在result被调用之后方法才返回, 这种情况适合open-session-in-view模式。 如果你想在result被调用之前做一些事情,你必须实现PreResultListener。
拦截器必须是线程安全的
对于struts2, 每个请求都会实例化一个action, 所以action不需要线程安全。 但是, 拦截器会在请求之间共享,所以,
拦截器必须线程安全。