Struts2拦截器
对于Struts中的标签这里就不一一列举了,标签也比较简单,所以就跳过,会用就好了,今天主要说下拦截器。拦截器interceptor类似于Filter,在执行Action方法前后执行,拦截器是一种AOP面向切片编程思想的编程方式。提供了一种机制使开发者能把相对独立的代码抽象出来,配置到Action前后执行。Filter中有Filter链在拦截器中有拦截栈,在Action前后被一次执行。Struts2内置了许多现成的拦截器,Struts2的某些功能如数据转换、数据校验等也是基于拦截器实现的。这些拦截器配置在struts-default.xml中,如果需要这些功能直接使用即可。下面举几个常用的拦截器的列子。
<interceptors> <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="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/> <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/> <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" /> <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" /> <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" /> <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="org.apache.struts2.interceptor.I18nInterceptor"/> <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/> <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/> <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/> <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/> <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/> <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/> <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/> <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/> <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/> <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="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" /> <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" /> <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" /> <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" /> <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" /> <!-- Basic stack --> <interceptor-stack name="basicStack"> <interceptor-ref name="exception"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> </interceptor-stack> <!-- Sample validation and workflow stack --> <interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="basicStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack> <!-- Sample file upload stack --> <interceptor-stack name="fileUploadStack"> <interceptor-ref name="fileUpload"/> <interceptor-ref name="basicStack"/> </interceptor-stack> <!-- Sample model-driven stack --> <interceptor-stack name="modelDrivenStack"> <interceptor-ref name="modelDriven"/> <interceptor-ref name="basicStack"/> </interceptor-stack> <!-- Sample action chaining stack --> <interceptor-stack name="chainStack"> <interceptor-ref name="chain"/> <interceptor-ref name="basicStack"/> </interceptor-stack> <!-- Sample i18n stack --> <interceptor-stack name="i18nStack"> <interceptor-ref name="i18n"/> <interceptor-ref name="basicStack"/> </interceptor-stack> <!-- An example of the paramsPrepareParams trick. This stack is exactly the same as the defaultStack, except that it includes one extra interceptor before the prepare interceptor: the params interceptor. This is useful for when you wish to apply parameters directly to an object that you wish to load externally (such as a DAO or database or service layer), but can't load that object until at least the ID parameter has been loaded. By loading the parameters twice, you can retrieve the object in the prepare() method, allowing the second params interceptor to apply the values on the object. --> <interceptor-stack name="paramsPrepareParamsStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="i18n"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="params"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> </interceptor-stack> <!-- A complete stack with all the common interceptors in place. Generally, this stack should be the one you use, though it may do more than you need. Also, the ordering can be switched around (ex: if you wish to have your servlet-related objects applied before prepare() is called, you'd need to move servletConfig interceptor up. This stack also excludes from the normal validation and workflow the method names input, back, and cancel. These typically are associated with requests that should not be validated. --> <interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="debugging"/> </interceptor-stack> <!-- The completeStack is here for backwards compatibility for applications that still refer to the defaultStack by the old name --> <interceptor-stack name="completeStack"> <interceptor-ref name="defaultStack"/> </interceptor-stack> <!-- Sample execute and wait stack. Note: execAndWait should always be the *last* interceptor. --> <interceptor-stack name="executeAndWaitStack"> <interceptor-ref name="execAndWait"> <param name="excludeMethods">input,back,cancel</param> </interceptor-ref> <interceptor-ref name="defaultStack"/> <interceptor-ref name="execAndWait"> <param name="excludeMethods">input,back,cancel</param> </interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="defaultStack"/>
拦截器 |
名字 |
说明 |
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 |
一、Token防重复提交拦截器
token拦截器用于保证表单只被提交一次,如果再次提交该表单,拦截器会拦截请求,防止提交重复数据。它的原理是显示表单的时候在session中对该表单做一个标记,该标记只能使用一次,使用过后就失效,从而保证表单最多只提交一次数据。重复提交数据会因为标记已失效而提交失败。首先定义Action。这里定义了一个TokenAction。
package com.cyw.test; import java.util.ArrayList; import java.util.List; import com.opensymphony.xwork2.ActionSupport; public class TokenAction extends ActionSupport { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String execute() throws Exception { return "success"; } }
2.表单设置
这里主要是在表单中增加 <struts:token></struts:token>标签。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="struts" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>注册页面</title> </head> <body> <struts:fielderror></struts:fielderror> <struts:form action="token" method="post"> <struts:token></struts:token> <struts:textfield name="name" label="用户名"></struts:textfield> <br/> <struts:submit value="注册"></struts:submit> </struts:form> </body> </html>
3.拦截器配置
在struts.xml中增加配置,配置token拦截器。Action中必须配置一个invalid.token的result页面。如果重复提交会跳转到该页面中。
<action name="token" class="com.cyw.test.TokenAction">
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="basicStack"></interceptor-ref>
<result name="success">/success.jsp</result>
<result name="input">/register.jsp</result>
<result name="invalid.token">/tokenInvalid.jsp</result>
</action>
4.结果
首先进入表单页面,提交表单
首次提交会提交成功,提交完成之后刷新页面此时会跳转到重复页面。
二、自定义拦截器
自定义拦截器一般继承抽象类AbstractInterceptor,该抽象类有3个方法。destroy()、init()、intercept(ActionInvocation arg0),最主要的是intercept(ActionInvocation arg0)方法。
Init方法在拦截器类被创建之后,在对Action镜像拦截之前调用,相当于一个post-constructor方法,使用这个方法可以给拦截器类做必要的初始话操作。
Destroy方法在拦截器被垃圾回收之前调用,用来回收init方法初始化的资源。
Intercept是拦截器的主要拦截方法,如果需要调用后续的Action或者拦截器,只需要在该方法中调用invocation.invoke()方法即可,在该方法调用的前后可以插入Action调用前后拦截器需要做的方法。如果不需要调用后续的方法,则返回一个String类型的对象即可。
下面的列子是对Action进行拦截判断是否有session,如果有则判断登录成功,没有则未登录。首先创建拦截器。
package com.cyw.test; import java.util.Map; import javax.servlet.http.*; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor extends AbstractInterceptor{ /** * */ private static final long serialVersionUID = 1L; @Override public void destroy() { System.out.println("MyInterceptor Destroy"); super.destroy(); } @Override public void init() { System.out.println("MyInterceptor init"); super.init(); } @Override public String intercept(ActionInvocation arg0) throws Exception { Map<String,Object> maps=arg0.getInvocationContext().getSession(); String sessionName=(String)maps.get("userName"); if(sessionName==null) { return "notlogin"; } else { return arg0.invoke(); } } }
然后创建了2个Action,一个登录一个登录后的。
package com.cyw.test; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { @Override public String execute() throws Exception { return "regist"; } }
package com.cyw.test; import com.opensymphony.xwork2.ActionSupport; public class IndexAction extends ActionSupport { @Override public String execute() throws Exception { return "success"; } }
在struts2.xml中注入拦截器。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <package name="default" namespace="" extends="struts-default"> <interceptors> <!-- login拦截器 --> <interceptor name="loginInterceptor" class="com.cyw.test.MyInterceptor"/> <interceptor-stack name="myInterceptorStack"> <interceptor-ref name="basicStack"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="loginInterceptor"/> </interceptor-stack> </interceptors> <global-results> <result name="notlogin">/notlogin.jsp</result> </global-results> <action name="login" class="com.cyw.test.LoginAction"> <result name="regist">/register.jsp</result> </action> <action name="index" class="com.cyw.test.IndexAction"> <interceptor-ref name="myInterceptorStack"></interceptor-ref> <result name="success">/success.jsp</result> </action> </package> </struts>
上面的xml中定义了一个拦截器栈,然后再Action中引用它,也可以在每个Action中一个一个的引入拦截器,同时可以使用<param>来对拦截器进行初始化参数。
实验结果:
由于对indexAction进行了拦截,所以判断session是否存在不存在跳转到notlogin.jsp页面。
三、拦截器与过滤器的比较
1、filter基于filter接口中的doFilter回调函数,interceptor则基于Java本身的反射机制;
2、filter是依赖于servlet容器的,没有servlet容器就无法回调doFilter方法,而interceptor与servlet无关;
3、filter的过滤范围比interceptor大,filter除了过滤请求外通过通配符可以保护页面、图片、文件等,而interceptor只能过滤请求,只对action起作用,在action之前开始,在action完成后结束(如被拦截,不执行action);
4、filter的过滤一般在加载的时候在init方法声明,而interceptor可以通过在xml声明是guest请求还是user请求来辨别是否过滤;
5、interceptor可以访问action上下文、值栈里的对象,而filter不能;
6、在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用一次。
作者:社会主义接班人
出处:http://www.cnblogs.com/5ishare/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。