Struts2拦截器是可插拨式的设计:如果需要使用某个拦截器,只需在配置文件中应用该拦截器即可;如果不需要使用,只需在配置文件中取消应用该拦截器。
Struts2拦截器由struts-default.xml、struts.xml等文件进行配置,所以开发者很容易扩展自己的拦截器。
1、内建拦截器
package继承了struts-default包就可使用struts-default.xml中定义的拦截器:
<!--<interceptor name="拦截器名" class="拦截器实现类"/>-->
<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="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="com.opensymphony.xwork2.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="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" />
2、拦截器配置和使用
1)定义
会在Action的excute方法执行之前被执行
<!-- 该元素可以出现0至1次-->
<interceptors>
<!-- interceptor元素和interceptor-stack至少出现其中之一,可以都出现-->
<!-- 该元素可以出现0至多次-->
<interceptor name="" class="">
<!-- 该元素可以出现0至多次-->
<param name="参数名">参数值</param>
</interceptor>
<!-- 该元素可以出现0至多次-->
<interceptor-stack name="">
<!-- 下面元素可以出现1到多次 -->
<interceptor-ref name="">
<!-- 该元素可以出现0至多次-->
<param name="参数名">参数值</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
2)使用 <!-- 定义Action,可以出现0到多次 -->
<action name="" class="" method="" converter="">
。。。
<!-- 下面元素可以出现0到多次 -->
<interceptor-ref name="拦截器名或拦截器栈名">
<!-- 该元素可以出现0至多次-->
<param name="参数名">动态参数</param>
</interceptor-ref>
。。。
</action>
<!-- 该元素可以出现0至1次-->
<default-interceptor-ref name="拦截器名或拦截器栈名">
<!-- 该元素可以出现0至多次-->
<param name="参数名">参数值</param>
</default-interceptor-ref>
3、自定义拦截器
1)编写实现com.opensymphony.xwork2.interceptor.Inteceptor接口的拦截器类
1 public class SimpleInterceptor 2 extends AbstractInterceptor 3 { 4 // 简单拦截器的名字 5 private String name; 6 // 为该简单拦截器设置名字的setter方法 7 public void setName(String name) 8 { 9 this.name = name; 10 } 11 public String intercept(ActionInvocation invocation) 12 throws Exception 13 { 14 // 取得被拦截的Action实例 15 LoginAction action = (LoginAction)invocation.getAction(); 16 // 打印执行开始的时间 17 System.out.println(name + " 拦截器的动作---------" + 18 "开始执行登录Action的时间为:" + new Date()); 19 // 取得开始执行Action的时间 20 long start = System.currentTimeMillis(); 21 // 执行该拦截器的后一个拦截器 22 // 如果该拦截器后没有其他拦截器,则直接执行Action的被拦截方法 23 String result = invocation.invoke(); 24 // 打印执行结束的时间 25 System.out.println(name + " 拦截器的动作---------" + 26 "执行完登录Action的时间为:" + new Date()); 27 long end = System.currentTimeMillis(); 28 System.out.println(name + " 拦截器的动作---------" + 29 "执行完该Action的时间为" + (end - start) + "毫秒"); 30 return result; 31 } 32 }
2) 在strutx.xml中注册上一步中定义的拦截器。
3)在Action中引用。
如果为Action指定了一个拦截器,则系统默认拦截器栈会失去作用,要继续使用则需要显示指定默认拦截器。
4、拦截方法的拦截器
1)重写doIntercept()方法
1 public class MyFilterInterceptor 2 extends MethodFilterInterceptor 3 { 4 // 简单拦截器的名字 5 private String name; 6 // 为该简单拦截器设置名字的setter方法 7 public void setName(String name) 8 { 9 this.name = name; 10 } 11 // 重写doIntercept()方法,实现对Action的拦截逻辑 12 public String doIntercept(ActionInvocation invocation) 13 throws Exception 14 { 15 // 取得被拦截的Action实例 16 LoginAction action = (LoginAction)invocation.getAction(); 17 // 打印执行开始的时间 18 System.out.println(name + " 拦截器的动作---------" 19 + "开始执行登录Action的时间为:" + new Date()); 20 // 取得开始执行Action的时间 21 long start = System.currentTimeMillis(); 22 // 执行该拦截器的后一个拦截器,或者直接指定Action的被拦截方法 23 String result = invocation.invoke(); 24 // 打印执行结束的时间 25 System.out.println(name + " 拦截器的动作---------" 26 + "执行完登录Action的时间为:" + new Date()); 27 long end = System.currentTimeMillis(); 28 // 打印执行该Action所花费的时间 29 System.out.println(name + " 拦截器的动作---------" 30 + "执行完该Action的时间为" + (end - start) + "毫秒"); 31 return result; 32 } 33 }
2)在配置文件中指定需要被拦截或不需要被拦截的方法:
<action name="login" class="org.crazyit.app.action.LoginAction">
。。。
<!-- 配置系统的默认拦截器 -->
<interceptor-ref name="defaultStack"/>
<!-- 应用自定义的mySimple拦截器 -->
<interceptor-ref name="mySimple">
<!-- 重新指定name属性的属性值 -->
<param name="name">改名后的拦截方法过滤拦截器</param>
<!-- 指定execute方法不需要被拦截 -->
<param name="excludeMethods">excludeMethod1,excludeMethod2</param>
<param name="includeMethods">includeMethod1,includeMethod2</param>
</interceptor-ref>
</action>
includeMethods和excludeMethods里有相同方法时,会拦截该方法。
能够指定方法过滤的拦截器有:
TokenInterceptor、TokenSessionInterceptor、DefaultWorkflowInterceptor、ValidationInterceptor
5、拦截器的执行顺序
通常认为:先配置,先执行,但也有特殊情况。Action中可以多次使用同一个拦截器,对于excute()方法前的动作,配置在前面的拦截器先起作用,对于在之后的动作,配置在后面的拦截器先起作用。
6、拦截器结果的监听器
定义拦截结果监听器,需实现PreResultListener接口。
1 public class MyPreResultListener 2 implements PreResultListener 3 { 4 // 定义在处理Result之前的行为 5 public void beforeResult(ActionInvocation invocation 6 ,String resultCode) 7 { 8 // 打印出执行结果 9 System.out.println("返回的逻辑视图为:" + resultCode); 10 // try 11 // { 12 // invocation.invoke(); 13 // } 14 // catch (Exception ex) 15 // { 16 // ex.printStackTrace(); 17 // } 18 // finally 19 // { 20 // } 21 } 22 }
1 public class BeforeResultInterceptor 2 extends AbstractInterceptor 3 { 4 public String intercept(ActionInvocation invocation) 5 throws Exception 6 { 7 // 将一个拦截结果的监听器注册给该拦截器 8 invocation.addPreResultListener(new MyPreResultListener()); 9 System.out.println("execute方法执行之前的拦截..."); 10 // 调用下一个拦截器,或者Action的被拦截方法 11 String result = invocation.invoke(); 12 System.out.println("execute方法执行之后的拦截..."); 13 return result; 14 } 15 }
执行结果:
excute方法执行之前的拦截...
进入excute方法执行体......
返回的逻辑视图为:success
excute方法执行之后的拦截...
拦截结果监听器的beforeResult方法可以获得ActionInvocation实例,但是千万不能通过该实例再次调用invoke(),如果调用,会再次进入Action,这样就会进入死循环。
7、覆盖拦截器栈里特定拦截器的参数
在<interceptor-ref../>的<param../>元素里使用<拦截器名>.<参数名>这种形式指定想要拦截的参数。
(因为同一个拦截器栈里,不同拦截器可能有相同属性)
8、使用拦截器完成权限控制
LoginAction类
1 public class LoginAction extends ActionSupport 2 { 3 private String username; 4 private String password; 5 6 // username的setter和getter方法 7 public void setUsername(String username) 8 { 9 this.username = username; 10 } 11 public String getUsername() 12 { 13 return this.username; 14 } 15 16 // password的setter和getter方法 17 public void setPassword(String password) 18 { 19 this.password = password; 20 } 21 public String getPassword() 22 { 23 return this.password; 24 } 25 26 public String execute() throws Exception 27 { 28 System.out.println("进入execute方法执行体.........."); 29 if (getUsername().equals("crazyit.org") 30 && getPassword().equals("leegang") ) 31 { 32 ActionContext ctx = ActionContext.getContext(); 33 Map<String,Object> session = ctx.getSession(); 34 session.put("user" , getUsername()); 35 return SUCCESS; 36 } 37 return ERROR; 38 } 39 }
AuthorityInterceptor类
// 权限检查拦截器继承AbstractInterceptor类 public class AuthorityInterceptor extends AbstractInterceptor { // 拦截Action处理的拦截方法 public String intercept(ActionInvocation invocation) throws Exception { // 取得请求相关的ActionContext实例 ActionContext ctx = invocation.getInvocationContext(); Map session = ctx.getSession(); // 取出Session里的user属性 String user = (String)session.get("user"); //如果没有登录,或者登录所用的用户名不是crazyit.org,都返回重新登录 if (user != null && user.equals("crazyit.org") ) { return invocation.invoke(); } // 如果没有登录,将服务器提示放入ActionContext中 ctx.put("tip" ,"您还没有登录,请输入crazyit.org,leegang登录系统"); // 返回login的逻辑视图 return Action.LOGIN; } }
struts.xml
1 <?xml version="1.0" encoding="GBK"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <constant name="struts.i18n.encoding" value="GBK"/> 7 8 <package name="lee" extends="struts-default"> 9 <!-- 用户拦截器定义在该元素下 --> 10 <interceptors> 11 <!-- 定义了一个名为authority的拦截器 --> 12 <interceptor name="authority" 13 class="org.crazyit.app.interceptor.AuthorityInterceptor"/> 14 </interceptors> 15 16 <!-- 定义全局Result --> 17 <global-results> 18 <!-- 当返回login视图名时,转入loginForm.jsp页面 --> 19 <result name="login">/WEB-INF/content/loginForm.jsp</result> 20 </global-results> 21 22 <action name="login" class="org.crazyit.app.action.LoginAction"> 23 <result name="error">/WEB-INF/content//error.jsp</result> 24 <result>/WEB-INF/content/welcome.jsp</result> 25 </action> 26 <!-- 定义一个名为viewBook的Action,其实现类为ActionSupport --> 27 <action name="viewBook"> 28 <!-- 返回success视图名时,转入viewBook.jsp页面 --> 29 <result>/WEB-INF/content/viewBook.jsp</result> 30 <interceptor-ref name="defaultStack"/> 31 <!-- 应用自定义拦截器 --> 32 <interceptor-ref name="authority"/> 33 </action> 34 <action name="*"> 35 <result>/WEB-INF/content/{1}.jsp</result> 36 </action> 37 </package> 38 </struts>