Struts 2 struts.xml详解(三)
拦截器(Interceptor)配置
上节简单地介绍了Action的配置,这节简单介绍一下拦截器的配置。
1 拦截器栈的配置
顾名思义,拦截器就是在action的执行前后实行拦截,加入某些操作。拦截器类似于servlet的过滤器。它们是按照定义的顺序依次执行的。每一个拦截器访问的都是相同的ActionInvocation,就像每个过滤器访问的都是同一个Request。拦截器是通过拦截器栈进行组织的,拦截器栈组织了一系列的拦截器的集合。
查看struts-default.xml文件的struts-default包,可以看到有两个元素<interceptors>和<interceptor-stack>。
<interceptors>元素:定义拦截器的名字和类
<interceptor-stack>元素:将特定的拦截器和拦截器栈组织在一起(拦截器栈中可以包含拦截器栈)
在struts-default.xml文件中已经定义了一些拦截器:
<interceptor name ="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor" /> <interceptor name ="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> <interceptor name ="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor" /> <interceptor name ="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> <interceptor name ="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" /> <interceptor name ="debugging" class ="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"/> <interceptor name ="external-ref" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/> <interceptor name ="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor" /> <interceptor name ="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> <interceptor name ="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor" /> <interceptor name ="i18n" class ="com.opensymphony.xwork2.interceptor.I18nInterceptor"/> <interceptor name ="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor" /> <interceptor name ="model-driven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor" /> <interceptor name ="scoped-model-driven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> <interceptor name ="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor" /> <interceptor name ="prepare" class ="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> <interceptor name ="static-params" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> <interceptor name ="scope" class="org.apache.struts2.interceptor.ScopeInterceptor" /> <interceptor name ="servlet-config" class="org.apache.struts2.interceptor.ServletConfigInterceptor" /> <interceptor name ="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/> <interceptor name ="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor" /> <interceptor name ="token" class="org.apache.struts2.interceptor.TokenInterceptor" /> <interceptor name ="token-session" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor" /> <interceptor name ="validation" class="com.opensymphony.xwork2.validator.ValidationInterceptor" /> <interceptor name ="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/> <interceptor name ="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" /> <interceptor name ="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" /> <interceptor name ="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor"/>
每个拦截器的定义包含了一个唯一的名字和拦截器类的全名(具体包名和类名)。
在struts-default.xm中已经配置了以上的拦截器。如果您想要使用上述拦截器,只需要在应用程序struts.xml文件中通过“<include file="struts-default.xml" />”将struts-default.xml文件包含进来,并继承其中的struts-default包(package),最后在定义Action时,使用“<interceptor-ref name="xx" />”引用拦截器或拦截器栈(interceptor stack)。一旦您继承了struts-default包(package),所有Action都会调用拦截器栈——defaultStack。当然,在Action配置中加入“<interceptor-refname="xx" />”可以覆盖defaultStack。
注:一旦在action中声明了任何一个拦截器,就得声明所有这个action要引用的拦截器,因为默认拦截器已经被覆盖了。
Struts2提供的拦截器功能说明:
拦截器 | 名字 | 说明 |
Alias Interceptor | alias | 在不同请求之间将请求参数在不同名字件转换,请求内容不变 |
Chaining Interceptor | chain | 让前一个Action的属性可以被后一个Action访问,现在和chain类型的result(<result type=”chain”>)结合使用。 |
Checkbox Interceptor | checkbox | 添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的checkbox。 |
Cookies Interceptor | cookies | 使用配置的name,value来是指cookies |
Conversion Error Interceptor | conversionError | 将错误从ActionContext中添加到Action的属性字段中。 |
Create Session Interceptor | createSession | 自动的创建HttpSession,用来为需要使用到HttpSession的拦截器服务。 |
Debugging Interceptor | debugging | 提供不同的调试用的页面来展现内部的数据状况。 |
Execute and Wait Interceptor | execAndWait | 在后台执行Action,同时将用户带到一个中间的等待页面。 |
Exception Interceptor | exception | 将异常定位到一个画面 |
File Upload Interceptor | fileUpload | 提供文件上传功能 |
I18n Interceptor | i18n | 记录用户选择的locale |
Logger Interceptor | logger | 输出Action的名字 |
Message Store Interceptor | store | 存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。 |
Model Driven Interceptor | model-driven | 如果一个类实现了ModelDriven,将getModel得到的结果放在Value Stack中。 |
Scoped Model Driven | scoped-model-driven | 如果一个Action实现了ScopedModelDriven,则这个拦截器会从相应的Scope中取出model调用Action的setModel方法将其放入Action内部。 |
Parameters Interceptor | params | 将请求中的参数设置到Action中去。 |
Prepare Interceptor | prepare | 如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。 |
Scope Interceptor | scope | 将Action状态存入session和application的简单方法。 |
Servlet Config Interceptor | servletConfig | 提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方式访问。 |
Static Parameters Interceptor | staticParams | 从struts.xml文件中将<action>中的<param>中的内容设置到对应的Action中。 |
Roles Interceptor | roles | 确定用户是否具有JAAS指定的Role,否则不予执行。 |
Timer Interceptor | timer | 输出Action执行的时间 |
Token Interceptor | token | 通过Token来避免双击 |
Token Session Interceptor | tokenSession | 和Token Interceptor一样,不过双击的时候把请求的数据存储在Session中 |
Validation Interceptor | validation | 使用action-validation.xml文件中定义的内容校验提交的数据。 |
Workflow Interceptor | workflow | 调用Action的validate方法,一旦有错误返回,重新定位到INPUT画面 |
Parameter Filter Interceptor | N/A | 从参数列表中删除不必要的参数 |
Profiling Interceptor | profiling | 通过参数激活profile |
拦截器栈组织了一系类拦截器,例如,Struts 2 定义了一个名位basicStack的拦截器栈:
<interceptor-stack name="basicStack"> <interceptor-ref name="exception"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> </interceptor-stack>
<interceptor-ref>是用来引用特定的拦截器或拦截器栈。
在validationWorkflowStack的定义中就引用了拦截器栈basicStack。
<interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="basicStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack>
2 拦截器的配置
拦截器可以通过<param>元素来配置参数。例如,我们可以看到validation的验证可以跳过某一个action的input()方法(对input()方法不执行验证)。配置如下:
<interceptor-stack name="validationWorkflowStack"> ... <interceptor-ref name="validation"> <param name="excludeMethods"> input,back,cancel,browse </param> </interceptor-ref> ...
这是因为validation拦截器是MethodFilterInterceptor的子类,MethodFilterInterceptor定义了一个excludeMethods的参数(还有includeMethods参数)。这个参数是以逗号分隔符解析出一系列不进行拦截的方法名的。以上的配置就是对input,back,cancel,browse等方法不进行拦截验证。
假设已经定义了一个拦截器栈defaultStack并且该拦截器栈包含了validation拦截器,而且我们有一个action要用到defaultStack拦截器栈,但是它有一个方法doNotValidate()不需要进行validation验证,怎么办呢?
也许你会这样配置:
<action name="errorConfiguration" class="com.stuqbx.web.action.ErrorAction"> <interceptor-ref name="validation"> <param name="excludeMethods"> input,back,cancel,browse,doNotValidate </param> </interceptor-ref> </action>
但是,这样配置运行之后,会发现其他的拦截器不起作用了,如前面所说的,action中一旦声明了拦截器,就得把要用到 拦截器都声明了。为此,可能要把defaultStack中所有的拦截器都在声明一遍,这太麻烦了。其实,我们还可以这样:
<action name="correctConfiguration" class="com.stuqbx.web.action.CorrectAction"> <interceptor-ref name="defaultStack"> <param name="validation.excludeMethods"> input,back,cancel,browse,doNotValidate </param> </interceptor-ref> </action>
这配置了一个action,该action用到了defaultStack拦截器栈,并且为其中的validation拦截器的excludeMethods参数配置了相应的值。配置的语法很简单,用interceptorName.parameterName作为param的name。还有如果在action中用到了一个拦截器栈,这个拦截器栈中又引用了多个拦截器栈,也可以为其中的某些拦截器配置相应的参数,语法为:stackName.interceptorName.parameterName。
3 默认拦截器
在package中可以用<default-interceptor-ref>来定义默认的拦截器。例如,在struts-default包中就定义了默认的拦截器:
<package name="struts-default" abstract="true"> <!-- ... --> <default-interceptor-ref name="defaultStack"/> </package>
4 拦截器工作原理
所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor。该接口提供了三个方法:
void init(); 在该拦截器被初始化之后,在该拦截器执行拦截之前,系统回调该方法。对于每个拦截器而言,此方法只执行一次。
void destroy();该方法跟init()方法对应。在拦截器实例被销毁之前,系统将回调该方法。
String intercept(ActionInvocation invocation) throws Exception; 该方法是用户需要实现的拦截动作。该方法会返回一个字符串作为逻辑视图。
除此之外,继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor是更简单的一种实现拦截器类的方式,因为此类提供了init()和destroy()方法的空实现,这样我们只需要实现intercept方法。
有些拦截器处理是跟action的调用无关的,有些拦截器只有在action实现了某些特定的接口时才执行。ActionInvocation有一个action的属性,存储了被调用的action的了实例。通过用instanceof检查是被调用的action是哪一个,拦截器就可以决定是否拦截处理。
在自定义拦截器时,拦截器必须是无状态的,不要使用在API提供的ActionInvocation之外的任何东西。拦截器是无状态的是因为Struts 2不能保证为每一个请求或者action创建一个拦截器的实例,所以如果拦截器带有状态,会引发并发问题。