Struts2学习之路(8)拦截器

Struts2拦截器详解
基本概述
     拦截器,在 AOP(Aspect-Oriented Programming)中用于在某个方法或宇段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
     在 Webwork 的中文文档的解释为一一拦截器是动态拦截Action调用的对象。它提供了一种机制,可以使开发者能够定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。
     拦截器链(Interceptor Chain,在Struts2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器的实现原理
     大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2会查找配置 文件,并根据其配置实例化相对应的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。
     Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2 拦截器链中的拦截器就会按其之前定义的顺序被调用。

Struts2的执行流程

步骤:
1、客户端请求,生成相应的HttpServletRequest对象
2、Struts2核心过滤器,StrutsPrepareAndExecuteFilter进行拦截,(如果满足要求,进行拦截,不满足要求,放行)
3、ActionMapper动作映射类,将请求的路径与struts.xml中的配置进行对比,找到匹配的动作类
4、经过核心过滤器,然后创建匹配的动作类的代理类对象,进行一系列的配置,(读取配置文件struts.xml,确定执行那个方法)
5、通过一些拦截器,对数据进行预处理,比如说请求参数的封装就是在这进行
6、进入动作方法,进行业务处理
7、动作方法返回结果视图的名字,到ActionMapper找到对应的结果视图,进行结果视图预处理
8、反向经过5中的拦截器
9、生成HttpServletResponse对象,返回给客户端。

自定义拦截器
     如果需要使用自定义拦截器,那么就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。

Interceptor接口定义

    
    
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import java.io.Serializable;
  4. public interface Interceptor extends Serializable {
  5. void destroy();
  6. void init();
  7. String intercept(ActionInvocation invocation) throws Exception;
  8. }

该接口提供了三个方法,其具体介绍如下:
  • void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。
  • void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。
  • String intercept(Actionlnvocation invocation) throws Exception:该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参 数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。
PS:注意,通过之上的Struts2执行流程和intercept()方法,可以知道,在使用invocation.invoke()时,可以不直接返回,而是放行前拦截,执行action,返回视图后拦截。
具体如下伪代码:

    
    
  1. // 放行前执行拦截操作
  2. String invoke = invocation.invoke();
  3. // 返回视图后拦截操作
  4. return invoke;

     如果需要自定义拦截器,只需要实现 Interceptor接口的三个方法即可。然而在实际开发过程中,除了实现Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter。该类实现了Interceptor接口,并且提供了init()方法和destroyO()方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。

AbstractInterceptor类定义

    
    
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. public abstract class AbstractInterceptor implements Interceptor {
  4. public void init() {}
  5. public void destroy() {}
  6. public abstract String intercept(ActionInvocation invocation) throws Exception;
  7. }

拦截器的继承关系



拦截器实现步骤
  • 第一步:定义一个拦截器类
               编写一个普通类,继承AbstractInterceptor。并且提供抽象方法的实现。 还可以继承MethodFilterInterceptor。
  • 第二步:配置拦截器
    • 声明拦截器
                     建立一个名称和一个拦截器类的对应关系。



    
    
  1. <interceptors>
  2. <interceptor name="指定一个名称" class="全类名"/>
  3. </interceptors>


    • 引用拦截器
                在action标签中使用

<interceptor-ref name="引用指定的名称"/>
    
    


自定义拦截器的细节

  • 如何放行
               invocation.invoke();//放行

  • 拦截器的执行
               访问动作方法之前会拦截。

               访问完结果视图之后还会拦截。

  • 放行方法的返回值
               动作方法的返回值。

               我们通过手动修改返回值,不能控制最终页面的转向。

在放行之前,拦截器的返回值可以控制显示哪个结果视图.一旦放行之后,它一定会显示动作方法返回值所匹配的结果视图,此时不管拦截器返回什么内容
* 比如执行这个Action
* public String Demo1(){
name = “123”;
return SUCCESS;
}
而拦截器如下:
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println(“拦截器起作用了”);
//拦截器放行了
String iv = invocation.invoke();
System.out.println(“拦截器放行了”);
//放行
return “error”;
}
那么它会跳转到哪个页面呢?因为在拦截器中先放行,再return,所以会跳转到success.jsp中,而不是error.jsp
为什么会这样?在执行invocation.invoke()时,会把success页面的内容存到缓存中,return时,直接从缓存显示出来

  • 多个拦截器的执行顺序问题

               是由使用的顺序决定。与声明顺序无关。

拦截器栈
     在实际开发中,经常需要在Action执行前同时执行多个拦截动作,如 : 用户登录检查 、登录日志记录以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个 Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。
     定义拦截器栈使用<interceptors>元素和<interceptor-stack>子元素,当配置多个拦截器时,需要使用<interceptor-ref>元素来指定多个拦截器。并且拦截器栈是可以嵌套的。


    
    
  1. <interceptors>
  2. <!-- 定义一个拦截器栈:包含权限拦截器和默认拦截器栈 -->
  3. <interceptor-stack name="myDefaultStack">
  4. <interceptor-ref name="privilegeInterceptor1"/>
  5. <interceptor-ref name="defaultStack"/>
  6. </interceptor-stack>
  7. </interceptors>


源码中的拦截器及拦截器栈

struts-default.xml文件中的拦截器


    
    
  1. <package name="struts-default" abstract="true">
  2. ........
  3. <interceptors>
  4. <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
  5. <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
  6. <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
  7. <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
  8. <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
  9. <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
  10. <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
  11. <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
  12. <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
  13. <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
  14. <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
  15. <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
  16. <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
  17. <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
  18. <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
  19. <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
  20. <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
  21. <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
  22. <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
  23. <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
  24. <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
  25. <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
  26. <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
  27. <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
  28. <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
  29. <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
  30. <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
  31. <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
  32. <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
  33. <interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
  34. <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
  35. <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
  36. <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
  37. <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
  38. <interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />
  39. <!-- Basic stack -->
  40. <interceptor-stack name="basicStack">
  41. <interceptor-ref name="exception"/>
  42. <interceptor-ref name="servletConfig"/>
  43. <interceptor-ref name="prepare"/>
  44. <interceptor-ref name="checkbox"/>
  45. <interceptor-ref name="datetime"/>
  46. <interceptor-ref name="multiselect"/>
  47. <interceptor-ref name="actionMappingParams"/>
  48. <interceptor-ref name="params"/>
  49. <interceptor-ref name="conversionError"/>
  50. <interceptor-ref name="deprecation"/>
  51. </interceptor-stack>
  52. <!-- Sample validation and workflow stack -->
  53. <interceptor-stack name="validationWorkflowStack">
  54. <interceptor-ref name="basicStack"/>
  55. <interceptor-ref name="validation"/>
  56. <interceptor-ref name="workflow"/>
  57. </interceptor-stack>
  58. <!-- Sample file upload stack -->
  59. <interceptor-stack name="fileUploadStack">
  60. <interceptor-ref name="fileUpload"/>
  61. <interceptor-ref name="basicStack"/>
  62. </interceptor-stack>
  63. <!-- Sample model-driven stack -->
  64. <interceptor-stack name="modelDrivenStack">
  65. <interceptor-ref name="modelDriven"/>
  66. <interceptor-ref name="basicStack"/>
  67. </interceptor-stack>
  68. <!-- Sample action chaining stack -->
  69. <interceptor-stack name="chainStack">
  70. <interceptor-ref name="chain"/>
  71. <interceptor-ref name="basicStack"/>
  72. </interceptor-stack>
  73. <!-- Sample i18n stack -->
  74. <interceptor-stack name="i18nStack">
  75. <interceptor-ref name="i18n"/>
  76. <interceptor-ref name="basicStack"/>
  77. </interceptor-stack>
  78. <!-- An example of the paramsPrepareParams trick. This stack
  79. is exactly the same as the defaultStack, except that it
  80. includes one extra interceptor before the prepare interceptor:
  81. the params interceptor.
  82. This is useful for when you wish to apply parameters directly
  83. to an object that you wish to load externally (such as a DAO
  84. or database or service layer), but can't load that object
  85. until at least the ID parameter has been loaded. By loading
  86. the parameters twice, you can retrieve the object in the
  87. prepare() method, allowing the second params interceptor to
  88. apply the values on the object. -->
  89. <interceptor-stack name="paramsPrepareParamsStack">
  90. <interceptor-ref name="exception"/>
  91. <interceptor-ref name="alias"/>
  92. <interceptor-ref name="i18n"/>
  93. <interceptor-ref name="checkbox"/>
  94. <interceptor-ref name="datetime"/>
  95. <interceptor-ref name="multiselect"/>
  96. <interceptor-ref name="params"/>
  97. <interceptor-ref name="servletConfig"/>
  98. <interceptor-ref name="prepare"/>
  99. <interceptor-ref name="chain"/>
  100. <interceptor-ref name="modelDriven"/>
  101. <interceptor-ref name="fileUpload"/>
  102. <interceptor-ref name="staticParams"/>
  103. <interceptor-ref name="actionMappingParams"/>
  104. <interceptor-ref name="params"/>
  105. <interceptor-ref name="conversionError"/>
  106. <interceptor-ref name="validation">
  107. <param name="excludeMethods">input,back,cancel,browse </param>
  108. </interceptor-ref>
  109. <interceptor-ref name="workflow">
  110. <param name="excludeMethods">input,back,cancel,browse </param>
  111. </interceptor-ref>
  112. </interceptor-stack>
  113. <!-- A complete stack with all the common interceptors in place.
  114. Generally, this stack should be the one you use, though it
  115. may do more than you need. Also, the ordering can be
  116. switched around (ex: if you wish to have your servlet-related
  117. objects applied before prepare() is called, you'd need to move
  118. servletConfig interceptor up.
  119. This stack also excludes from the normal validation and workflow
  120. the method names input, back, and cancel. These typically are
  121. associated with requests that should not be validated.
  122. -->
  123. <interceptor-stack name="defaultStack">
  124. <interceptor-ref name="exception"/>
  125. <interceptor-ref name="alias"/>
  126. <interceptor-ref name="servletConfig"/>
  127. <interceptor-ref name="i18n"/>
  128. <interceptor-ref name="prepare"/>
  129. <interceptor-ref name="chain"/>
  130. <interceptor-ref name="scopedModelDriven"/>
  131. <interceptor-ref name="modelDriven"/>
  132. <interceptor-ref name="fileUpload"/>
  133. <interceptor-ref name="checkbox"/>
  134. <interceptor-ref name="datetime"/>
  135. <interceptor-ref name="multiselect"/>
  136. <interceptor-ref name="staticParams"/>
  137. <interceptor-ref name="actionMappingParams"/>
  138. <interceptor-ref name="params"/>
  139. <interceptor-ref name="conversionError"/>
  140. <interceptor-ref name="validation">
  141. <param name="excludeMethods">input,back,cancel,browse </param>
  142. </interceptor-ref>
  143. <interceptor-ref name="workflow">
  144. <param name="excludeMethods">input,back,cancel,browse </param>
  145. </interceptor-ref>
  146. <interceptor-ref name="debugging"/>
  147. <interceptor-ref name="deprecation"/>
  148. </interceptor-stack>
  149. <!-- The completeStack is here for backwards compatibility for
  150. applications that still refer to the defaultStack by the
  151. old name -->
  152. <interceptor-stack name="completeStack">
  153. <interceptor-ref name="defaultStack"/>
  154. </interceptor-stack>
  155. <!-- Sample execute and wait stack.
  156. Note: execAndWait should always be the last interceptor. -->
  157. <interceptor-stack name="executeAndWaitStack">
  158. <interceptor-ref name="execAndWait">
  159. <param name="excludeMethods">input,back,cancel </param>
  160. </interceptor-ref>
  161. <interceptor-ref name="defaultStack"/>
  162. <interceptor-ref name="execAndWait">
  163. <param name="excludeMethods">input,back,cancel </param>
  164. </interceptor-ref>
  165. </interceptor-stack>
  166. </interceptors>
  167. <default-interceptor-ref name="defaultStack"/>
  168. ......
  169. </package>


由该文件,可以得出核心的默认拦截器配置如下:


    
    
  1. <package name="struts-default" abstract="true">
  2. <interceptors>
  3. <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
  4. ......
  5. <interceptor-stack name="defaultStack">
  6. <interceptor-ref name="exception"/>
  7. <interceptor-ref name="alias"/>
  8. <interceptor-ref name="servletConfig"/>
  9. <interceptor-ref name="i18n"/>
  10. <interceptor-ref name="prepare"/>
  11. <interceptor-ref name="chain"/>
  12. <interceptor-ref name="scopedModelDriven"/>
  13. <interceptor-ref name="modelDriven"/>
  14. <interceptor-ref name="fileUpload"/>
  15. <interceptor-ref name="checkbox"/>
  16. <interceptor-ref name="datetime"/>
  17. <interceptor-ref name="multiselect"/>
  18. <interceptor-ref name="staticParams"/>
  19. <interceptor-ref name="actionMappingParams"/>
  20. <interceptor-ref name="params"/>
  21. <interceptor-ref name="conversionError"/>
  22. <interceptor-ref name="validation">
  23. <param name="excludeMethods">input,back,cancel,browse </param>
  24. </interceptor-ref>
  25. <interceptor-ref name="workflow">
  26. <param name="excludeMethods">input,back,cancel,browse </param>
  27. </interceptor-ref>
  28. <interceptor-ref name="debugging"/>
  29. <interceptor-ref name="deprecation"/>
  30. </interceptor-stack>
  31. </interceptors>
  32. <default-interceptor-ref name="defaultStack"/>
  33. </package>


PS:由该源码,可以知道struts2的一些像是代码封装之类的事情,就是通过拦截器做到的。如果我们需要使用自定义拦截器,那么最好是将默认的拦截器栈也包含进去,因为这样就不会丢失strut2框架提供的功能。


案例


    
    
  1. package com.pc.user.web.action;
  2. import com.opensymphony.xwork2.ActionSupport;
  3. /
  4. * 用户Action
  5. @author Switch
  6. * @data 2016年11月20日
  7. * @version V1.0
  8. /
  9. public class UserAction extends ActionSupport {
  10. private static final long serialVersionUID = 366851530423407749L;
  11. /
  12. 模拟保存用户
  13. * @return
  14. /
  15. public String saveUser() {
  16. System.out.println( "保存成功");
  17. return SUCCESS;
  18. }
  19. /
  20. 模拟删除用户
  21. @return
  22. /
  23. public String removeUser() {
  24. System.out.println( "删除成功");
  25. return SUCCESS;
  26. }
  27. }


    
    
  1. package com.pc.user.web.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
  4. /
  5. 拦截器1
  6. @author Switch
  7. * @data 2016年11月20日
  8. * @version V1.0
  9. */
  10. public class MyInterceptor1 extends AbstractInterceptor {
  11. private static final long serialVersionUID = - 623800184006159480L;
  12. @Override
  13. public String intercept(ActionInvocation invocation) throws Exception {
  14. System.out.println( "访问Action前,MyInterceptor1拦截了");
  15. // //放行:如果有下一个拦截器执行下一个拦截器,如果该拦截器是最后一个,则执行动作方法。
  16. String invoke = invocation.invoke();
  17. System.out.println( "访问Action后,MyInterceptor1拦截了");
  18. return invoke;
  19. }
  20. }


struts.xml


    
    
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. <struts>
  5. <constant name="struts.devMode" value="true"/>
  6. <!-- 定义一些公共的配置:针对当前web工程的 -->
  7. <package name="myDefaultPackage" extends="struts-default" abstract="true">
  8. <interceptors>
  9. <!-- 声明拦截器 -->
  10. <interceptor name="myInterceptor1" class="com.pc.user.web.interceptor.MyInterceptor1"/>
  11. </interceptors>
  12. </package>
  13. <package name="pack1" extends="myDefaultPackage" namespace="">
  14. <global-results>
  15. <result name="success" type="dispatcher">/success.jsp </result>
  16. </global-results>
  17. <!-- 用户保存 -->
  18. <action name="saveUser" class="com.pc.user.web.action.UserAction" method="saveUser">
  19. <!-- 使用拦截器 -->
  20. <interceptor-ref name="myInterceptor1"> </interceptor-ref>
  21. <result name="main" type="dispatcher">/main.jsp </result>
  22. </action>
  23. <!-- 用户删除 -->
  24. <action name="removeUser" class="com.pc.user.web.action.UserAction" method="removeUser"/>
  25. </package>
  26. </struts>


main.jsp


    
    
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>主页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/saveUser.action"</span>&gt;</span>用户保存<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"${pageContext.request.contextPath}/removeUser.action">用户删除 </a>
  10. </body>
  11. </html>


success.jsp


    
    
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>成功 </title>
  7. </head>
  8. <body>
  9. <h2>执行成功 </h2>
  10. <% System.out.println("执行成功"); %>
  11. </body>
  12. </html>


访问结果

访问Action前,MyInterceptor1拦截了 
保存成功
执行成功
访问Action后,MyInterceptor1拦截了

删除成功
执行成功


PS:可以看出,正如执行流程所示,拦截器在访问Action之前拦截了一次和返回视图之后拦截了一次。

扩展案例:MethodFilterInterceptor拦截器的使用
     MethodFilterInterceptor拦截器,提供了对指定方法集合的拦截和对指定方法集合的放行。
     先看看MethodFilterInterceptor的源码,可以发现该拦截器已经实现了intercept方法,并且提供了一个setIncludeMethods和一个setExcludeMethods来设置拦截方法集和不拦截方法集。并定义了一个doIntercept,提供给子类,作用与intercept方法一样。


    
    
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import com.opensymphony.xwork2.util.TextParseUtil;
  4. import com.opensymphony.xwork2.util.logging.Logger;
  5. import com.opensymphony.xwork2.util.logging.LoggerFactory;
  6. import java.util.Collections;
  7. import java.util.Set;
  8. public abstract class MethodFilterInterceptor extends AbstractInterceptor {
  9. protected transient Logger log = LoggerFactory.getLogger(getClass());
  10. protected Set<String> excludeMethods = Collections.emptySet();
  11. protected Set<String> includeMethods = Collections.emptySet();
  12. public void setExcludeMethods(String excludeMethods) {
  13. this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
  14. }
  15. public Set<String> getExcludeMethodsSet() {
  16. return excludeMethods;
  17. }
  18. public void setIncludeMethods(String includeMethods) {
  19. this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
  20. }
  21. public Set<String> getIncludeMethodsSet() {
  22. return includeMethods;
  23. }
  24. @Override
  25. public String intercept(ActionInvocation invocation) throws Exception {
  26. if (applyInterceptor(invocation)) {
  27. return doIntercept(invocation);
  28. }
  29. return invocation.invoke();
  30. }
  31. protected boolean applyInterceptor(ActionInvocation invocation) {
  32. String method = invocation.getProxy().getMethod();
  33. // ValidationInterceptor
  34. boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
  35. if (log.isDebugEnabled()) {
  36. if (!applyMethod) {
  37. log.debug( "Skipping Interceptor... Method [" + method + "] found in exclude list.");
  38. }
  39. }
  40. return applyMethod;
  41. }
  42. protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
  43. }


案例


    
    
  1. package com.pc.user.web.action;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.ActionSupport;
  4. /
  5. * 用户Action
  6. @author Switch
  7. * @data 2016年11月20日
  8. * @version V1.0
  9. /
  10. public class UserAction extends ActionSupport {
  11. private static final long serialVersionUID = 366851530423407749L;
  12. /
  13. 模拟登陆
  14. @return
  15. /
  16. public String login() {
  17. ActionContext.getContext().getSession().put( "loginUser", "switch");
  18. System.out.println( "登陆成功");
  19. return "main";
  20. }
  21. /
  22. 模拟保存用户
  23. @return
  24. /
  25. public String saveUser() {
  26. System.out.println( "保存成功");
  27. return SUCCESS;
  28. }
  29. /
  30. 模拟删除用户
  31. @return
  32. /
  33. public String removeUser() {
  34. System.out.println( "删除成功");
  35. return SUCCESS;
  36. }
  37. }


    
    
  1. package com.pc.user.web.interceptor;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.ActionInvocation;
  4. import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
  5. /*
  6. * 权限过滤器,实现登录验证
  7. * 通过实现方法过滤拦截器实现
  8. @author Switch
  9. * @data 2016年11月20日
  10. * @version V1.0
  11. */
  12. public class PrivilegeInterceptor extends MethodFilterInterceptor {
  13. private static final long serialVersionUID = - 623800184006159480L;
  14. @Override
  15. protected String doIntercept(ActionInvocation invocation) throws Exception {
  16. // 判断session中是否有用户数据
  17. ActionContext context = ActionContext.getContext();
  18. Object loginUser = context.getSession().get( "loginUser");
  19. // 用户不存在,则返回登录界面
  20. if (loginUser == null) {
  21. return "login";
  22. }
  23. // 放行
  24. return invocation.invoke();
  25. }
  26. }


struts.xml



    
    
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. <struts>
  5. <constant name="struts.devMode" value="true"/>
  6. <!-- 定义一些公共的配置:针对当前web工程的 -->
  7. <package name="myDefaultPackage" extends="struts-default" abstract="true">
  8. <interceptors>
  9. <!-- 声明权限拦截器 -->
  10. <interceptor name="privilegeInterceptor1" class="com.pc.user.web.interceptor.PrivilegeInterceptor"/>
  11. <!-- 定义一个拦截器栈:包含权限拦截器和默认拦截器栈 -->
  12. <interceptor-stack name="myDefaultStack">
  13. <interceptor-ref name="privilegeInterceptor1">
  14. <!-- 给拦截器注入参数:告知拦截器拦截哪些或者是排除哪些方法。挑少的写
  15. 传入参数的name是找MethodFilterInterceptor中setXXXX方法后面的部分。
  16. 传入参数的值写的是动作方法名称,如果是多个方法,以逗号分隔。
  17. <param name="excludeMethods">login</param> -->
  18. </interceptor-ref>
  19. <interceptor-ref name="defaultStack"/>
  20. </interceptor-stack>
  21. </interceptors>
  22. <!-- 定义默认拦截器栈:把myDefaultStack声明为默认拦截器栈 -->
  23. <default-interceptor-ref name="myDefaultStack" />
  24. </package>
  25. <package name="pack1" extends="myDefaultPackage" namespace="">
  26. <!-- 全局结果视图 -->
  27. <global-results>
  28. <result name="success" type="dispatcher">/success.jsp </result>
  29. <result name="login" type="redirect">/login.jsp </result>
  30. </global-results>
  31. <!-- 用户登录 -->
  32. <action name="login" class="com.pc.user.web.action.UserAction" method="login">
  33. <!-- 转发到主页 -->
  34. <result name="main" type="dispatcher">/main.jsp </result>
  35. <interceptor-ref name="myDefaultStack">
  36. <!-- 指定给过滤器栈中哪个过滤器设置参数 -->
  37. <param name="privilegeInterceptor1.excludeMethods">login </param>
  38. </interceptor-ref>
  39. </action>
  40. <!-- 用户保存 -->
  41. <action name="saveUser" class="com.pc.user.web.action.UserAction" method="saveUser"/>
  42. <!-- 用户删除 -->
  43. <action name="removeUser" class="com.pc.user.web.action.UserAction" method="removeUser"/>
  44. </package>
  45. </struts>


login.jsp


    
    
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>登录页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/login.action">用户登录 </a>
  10. </body>
  11. </html>


main.jsp



    
    
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>主页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/saveUser.action"</span>&gt;</span>用户保存<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"${pageContext.request.contextPath}/removeUser.action">用户删除 </a>
  10. </body>
  11. </html>


success.jsp


    
    
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>成功 </title>
  7. </head>
  8. <body>
  9. <h2>执行成功 </h2>
  10. <% System.out.println("执行成功"); %>
  11. </body>
  12. </html>





Struts2拦截器详解
基本概述
     拦截器,在 AOP(Aspect-Oriented Programming)中用于在某个方法或宇段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
     在 Webwork 的中文文档的解释为一一拦截器是动态拦截Action调用的对象。它提供了一种机制,可以使开发者能够定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。
     拦截器链(Interceptor Chain,在Struts2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器的实现原理
     大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2会查找配置 文件,并根据其配置实例化相对应的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。
     Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2 拦截器链中的拦截器就会按其之前定义的顺序被调用。

Struts2的执行流程

步骤:
1、客户端请求,生成相应的HttpServletRequest对象
2、Struts2核心过滤器,StrutsPrepareAndExecuteFilter进行拦截,(如果满足要求,进行拦截,不满足要求,放行)
3、ActionMapper动作映射类,将请求的路径与struts.xml中的配置进行对比,找到匹配的动作类
4、经过核心过滤器,然后创建匹配的动作类的代理类对象,进行一系列的配置,(读取配置文件struts.xml,确定执行那个方法)
5、通过一些拦截器,对数据进行预处理,比如说请求参数的封装就是在这进行
6、进入动作方法,进行业务处理
7、动作方法返回结果视图的名字,到ActionMapper找到对应的结果视图,进行结果视图预处理
8、反向经过5中的拦截器
9、生成HttpServletResponse对象,返回给客户端。

自定义拦截器
     如果需要使用自定义拦截器,那么就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。

Interceptor接口定义

  
  
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import java.io.Serializable;
  4. public interface Interceptor extends Serializable {
  5. void destroy();
  6. void init();
  7. String intercept(ActionInvocation invocation) throws Exception;
  8. }

该接口提供了三个方法,其具体介绍如下:
  • void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。
  • void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。
  • String intercept(Actionlnvocation invocation) throws Exception:该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参 数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。
PS:注意,通过之上的Struts2执行流程和intercept()方法,可以知道,在使用invocation.invoke()时,可以不直接返回,而是放行前拦截,执行action,返回视图后拦截。
具体如下伪代码:

  
  
  1. // 放行前执行拦截操作
  2. String invoke = invocation.invoke();
  3. // 返回视图后拦截操作
  4. return invoke;

     如果需要自定义拦截器,只需要实现 Interceptor接口的三个方法即可。然而在实际开发过程中,除了实现Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter。该类实现了Interceptor接口,并且提供了init()方法和destroyO()方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。

AbstractInterceptor类定义

  
  
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. public abstract class AbstractInterceptor implements Interceptor {
  4. public void init() {}
  5. public void destroy() {}
  6. public abstract String intercept(ActionInvocation invocation) throws Exception;
  7. }

拦截器的继承关系



拦截器实现步骤
  • 第一步:定义一个拦截器类
               编写一个普通类,继承AbstractInterceptor。并且提供抽象方法的实现。 还可以继承MethodFilterInterceptor。
  • 第二步:配置拦截器
    • 声明拦截器
                     建立一个名称和一个拦截器类的对应关系。



  
  
  1. <interceptors>
  2. <interceptor name="指定一个名称" class="全类名"/>
  3. </interceptors>


    • 引用拦截器
                在action标签中使用

<interceptor-ref name="引用指定的名称"/>
  
  


自定义拦截器的细节

  • 如何放行
               invocation.invoke();//放行

  • 拦截器的执行
               访问动作方法之前会拦截。

               访问完结果视图之后还会拦截。

  • 放行方法的返回值
               动作方法的返回值。

               我们通过手动修改返回值,不能控制最终页面的转向。

在放行之前,拦截器的返回值可以控制显示哪个结果视图.一旦放行之后,它一定会显示动作方法返回值所匹配的结果视图,此时不管拦截器返回什么内容
* 比如执行这个Action
* public String Demo1(){
name = “123”;
return SUCCESS;
}
而拦截器如下:
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println(“拦截器起作用了”);
//拦截器放行了
String iv = invocation.invoke();
System.out.println(“拦截器放行了”);
//放行
return “error”;
}
那么它会跳转到哪个页面呢?因为在拦截器中先放行,再return,所以会跳转到success.jsp中,而不是error.jsp
为什么会这样?在执行invocation.invoke()时,会把success页面的内容存到缓存中,return时,直接从缓存显示出来

  • 多个拦截器的执行顺序问题

               是由使用的顺序决定。与声明顺序无关。

拦截器栈
     在实际开发中,经常需要在Action执行前同时执行多个拦截动作,如 : 用户登录检查 、登录日志记录以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个 Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。
     定义拦截器栈使用<interceptors>元素和<interceptor-stack>子元素,当配置多个拦截器时,需要使用<interceptor-ref>元素来指定多个拦截器。并且拦截器栈是可以嵌套的。


  
  
  1. <interceptors>
  2. <!-- 定义一个拦截器栈:包含权限拦截器和默认拦截器栈 -->
  3. <interceptor-stack name="myDefaultStack">
  4. <interceptor-ref name="privilegeInterceptor1"/>
  5. <interceptor-ref name="defaultStack"/>
  6. </interceptor-stack>
  7. </interceptors>


源码中的拦截器及拦截器栈

struts-default.xml文件中的拦截器


  
  
  1. <package name="struts-default" abstract="true">
  2. ........
  3. <interceptors>
  4. <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
  5. <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
  6. <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
  7. <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
  8. <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
  9. <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
  10. <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
  11. <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
  12. <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
  13. <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
  14. <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
  15. <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
  16. <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
  17. <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
  18. <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
  19. <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
  20. <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
  21. <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
  22. <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
  23. <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
  24. <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
  25. <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
  26. <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
  27. <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
  28. <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
  29. <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
  30. <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
  31. <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
  32. <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
  33. <interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
  34. <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
  35. <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
  36. <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
  37. <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
  38. <interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />
  39. <!-- Basic stack -->
  40. <interceptor-stack name="basicStack">
  41. <interceptor-ref name="exception"/>
  42. <interceptor-ref name="servletConfig"/>
  43. <interceptor-ref name="prepare"/>
  44. <interceptor-ref name="checkbox"/>
  45. <interceptor-ref name="datetime"/>
  46. <interceptor-ref name="multiselect"/>
  47. <interceptor-ref name="actionMappingParams"/>
  48. <interceptor-ref name="params"/>
  49. <interceptor-ref name="conversionError"/>
  50. <interceptor-ref name="deprecation"/>
  51. </interceptor-stack>
  52. <!-- Sample validation and workflow stack -->
  53. <interceptor-stack name="validationWorkflowStack">
  54. <interceptor-ref name="basicStack"/>
  55. <interceptor-ref name="validation"/>
  56. <interceptor-ref name="workflow"/>
  57. </interceptor-stack>
  58. <!-- Sample file upload stack -->
  59. <interceptor-stack name="fileUploadStack">
  60. <interceptor-ref name="fileUpload"/>
  61. <interceptor-ref name="basicStack"/>
  62. </interceptor-stack>
  63. <!-- Sample model-driven stack -->
  64. <interceptor-stack name="modelDrivenStack">
  65. <interceptor-ref name="modelDriven"/>
  66. <interceptor-ref name="basicStack"/>
  67. </interceptor-stack>
  68. <!-- Sample action chaining stack -->
  69. <interceptor-stack name="chainStack">
  70. <interceptor-ref name="chain"/>
  71. <interceptor-ref name="basicStack"/>
  72. </interceptor-stack>
  73. <!-- Sample i18n stack -->
  74. <interceptor-stack name="i18nStack">
  75. <interceptor-ref name="i18n"/>
  76. <interceptor-ref name="basicStack"/>
  77. </interceptor-stack>
  78. <!-- An example of the paramsPrepareParams trick. This stack
  79. is exactly the same as the defaultStack, except that it
  80. includes one extra interceptor before the prepare interceptor:
  81. the params interceptor.
  82. This is useful for when you wish to apply parameters directly
  83. to an object that you wish to load externally (such as a DAO
  84. or database or service layer), but can't load that object
  85. until at least the ID parameter has been loaded. By loading
  86. the parameters twice, you can retrieve the object in the
  87. prepare() method, allowing the second params interceptor to
  88. apply the values on the object. -->
  89. <interceptor-stack name="paramsPrepareParamsStack">
  90. <interceptor-ref name="exception"/>
  91. <interceptor-ref name="alias"/>
  92. <interceptor-ref name="i18n"/>
  93. <interceptor-ref name="checkbox"/>
  94. <interceptor-ref name="datetime"/>
  95. <interceptor-ref name="multiselect"/>
  96. <interceptor-ref name="params"/>
  97. <interceptor-ref name="servletConfig"/>
  98. <interceptor-ref name="prepare"/>
  99. <interceptor-ref name="chain"/>
  100. <interceptor-ref name="modelDriven"/>
  101. <interceptor-ref name="fileUpload"/>
  102. <interceptor-ref name="staticParams"/>
  103. <interceptor-ref name="actionMappingParams"/>
  104. <interceptor-ref name="params"/>
  105. <interceptor-ref name="conversionError"/>
  106. <interceptor-ref name="validation">
  107. <param name="excludeMethods">input,back,cancel,browse </param>
  108. </interceptor-ref>
  109. <interceptor-ref name="workflow">
  110. <param name="excludeMethods">input,back,cancel,browse </param>
  111. </interceptor-ref>
  112. </interceptor-stack>
  113. <!-- A complete stack with all the common interceptors in place.
  114. Generally, this stack should be the one you use, though it
  115. may do more than you need. Also, the ordering can be
  116. switched around (ex: if you wish to have your servlet-related
  117. objects applied before prepare() is called, you'd need to move
  118. servletConfig interceptor up.
  119. This stack also excludes from the normal validation and workflow
  120. the method names input, back, and cancel. These typically are
  121. associated with requests that should not be validated.
  122. -->
  123. <interceptor-stack name="defaultStack">
  124. <interceptor-ref name="exception"/>
  125. <interceptor-ref name="alias"/>
  126. <interceptor-ref name="servletConfig"/>
  127. <interceptor-ref name="i18n"/>
  128. <interceptor-ref name="prepare"/>
  129. <interceptor-ref name="chain"/>
  130. <interceptor-ref name="scopedModelDriven"/>
  131. <interceptor-ref name="modelDriven"/>
  132. <interceptor-ref name="fileUpload"/>
  133. <interceptor-ref name="checkbox"/>
  134. <interceptor-ref name="datetime"/>
  135. <interceptor-ref name="multiselect"/>
  136. <interceptor-ref name="staticParams"/>
  137. <interceptor-ref name="actionMappingParams"/>
  138. <interceptor-ref name="params"/>
  139. <interceptor-ref name="conversionError"/>
  140. <interceptor-ref name="validation">
  141. <param name="excludeMethods">input,back,cancel,browse </param>
  142. </interceptor-ref>
  143. <interceptor-ref name="workflow">
  144. <param name="excludeMethods">input,back,cancel,browse </param>
  145. </interceptor-ref>
  146. <interceptor-ref name="debugging"/>
  147. <interceptor-ref name="deprecation"/>
  148. </interceptor-stack>
  149. <!-- The completeStack is here for backwards compatibility for
  150. applications that still refer to the defaultStack by the
  151. old name -->
  152. <interceptor-stack name="completeStack">
  153. <interceptor-ref name="defaultStack"/>
  154. </interceptor-stack>
  155. <!-- Sample execute and wait stack.
  156. Note: execAndWait should always be the last interceptor. -->
  157. <interceptor-stack name="executeAndWaitStack">
  158. <interceptor-ref name="execAndWait">
  159. <param name="excludeMethods">input,back,cancel </param>
  160. </interceptor-ref>
  161. <interceptor-ref name="defaultStack"/>
  162. <interceptor-ref name="execAndWait">
  163. <param name="excludeMethods">input,back,cancel </param>
  164. </interceptor-ref>
  165. </interceptor-stack>
  166. </interceptors>
  167. <default-interceptor-ref name="defaultStack"/>
  168. ......
  169. </package>


由该文件,可以得出核心的默认拦截器配置如下:


  
  
  1. <package name="struts-default" abstract="true">
  2. <interceptors>
  3. <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
  4. ......
  5. <interceptor-stack name="defaultStack">
  6. <interceptor-ref name="exception"/>
  7. <interceptor-ref name="alias"/>
  8. <interceptor-ref name="servletConfig"/>
  9. <interceptor-ref name="i18n"/>
  10. <interceptor-ref name="prepare"/>
  11. <interceptor-ref name="chain"/>
  12. <interceptor-ref name="scopedModelDriven"/>
  13. <interceptor-ref name="modelDriven"/>
  14. <interceptor-ref name="fileUpload"/>
  15. <interceptor-ref name="checkbox"/>
  16. <interceptor-ref name="datetime"/>
  17. <interceptor-ref name="multiselect"/>
  18. <interceptor-ref name="staticParams"/>
  19. <interceptor-ref name="actionMappingParams"/>
  20. <interceptor-ref name="params"/>
  21. <interceptor-ref name="conversionError"/>
  22. <interceptor-ref name="validation">
  23. <param name="excludeMethods">input,back,cancel,browse </param>
  24. </interceptor-ref>
  25. <interceptor-ref name="workflow">
  26. <param name="excludeMethods">input,back,cancel,browse </param>
  27. </interceptor-ref>
  28. <interceptor-ref name="debugging"/>
  29. <interceptor-ref name="deprecation"/>
  30. </interceptor-stack>
  31. </interceptors>
  32. <default-interceptor-ref name="defaultStack"/>
  33. </package>


PS:由该源码,可以知道struts2的一些像是代码封装之类的事情,就是通过拦截器做到的。如果我们需要使用自定义拦截器,那么最好是将默认的拦截器栈也包含进去,因为这样就不会丢失strut2框架提供的功能。


案例


  
  
  1. package com.pc.user.web.action;
  2. import com.opensymphony.xwork2.ActionSupport;
  3. /
  4. * 用户Action
  5. @author Switch
  6. * @data 2016年11月20日
  7. * @version V1.0
  8. /
  9. public class UserAction extends ActionSupport {
  10. private static final long serialVersionUID = 366851530423407749L;
  11. /
  12. 模拟保存用户
  13. * @return
  14. /
  15. public String saveUser() {
  16. System.out.println( "保存成功");
  17. return SUCCESS;
  18. }
  19. /
  20. 模拟删除用户
  21. @return
  22. /
  23. public String removeUser() {
  24. System.out.println( "删除成功");
  25. return SUCCESS;
  26. }
  27. }


  
  
  1. package com.pc.user.web.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
  4. /
  5. 拦截器1
  6. @author Switch
  7. * @data 2016年11月20日
  8. * @version V1.0
  9. */
  10. public class MyInterceptor1 extends AbstractInterceptor {
  11. private static final long serialVersionUID = - 623800184006159480L;
  12. @Override
  13. public String intercept(ActionInvocation invocation) throws Exception {
  14. System.out.println( "访问Action前,MyInterceptor1拦截了");
  15. // //放行:如果有下一个拦截器执行下一个拦截器,如果该拦截器是最后一个,则执行动作方法。
  16. String invoke = invocation.invoke();
  17. System.out.println( "访问Action后,MyInterceptor1拦截了");
  18. return invoke;
  19. }
  20. }


struts.xml


  
  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. <struts>
  5. <constant name="struts.devMode" value="true"/>
  6. <!-- 定义一些公共的配置:针对当前web工程的 -->
  7. <package name="myDefaultPackage" extends="struts-default" abstract="true">
  8. <interceptors>
  9. <!-- 声明拦截器 -->
  10. <interceptor name="myInterceptor1" class="com.pc.user.web.interceptor.MyInterceptor1"/>
  11. </interceptors>
  12. </package>
  13. <package name="pack1" extends="myDefaultPackage" namespace="">
  14. <global-results>
  15. <result name="success" type="dispatcher">/success.jsp </result>
  16. </global-results>
  17. <!-- 用户保存 -->
  18. <action name="saveUser" class="com.pc.user.web.action.UserAction" method="saveUser">
  19. <!-- 使用拦截器 -->
  20. <interceptor-ref name="myInterceptor1"> </interceptor-ref>
  21. <result name="main" type="dispatcher">/main.jsp </result>
  22. </action>
  23. <!-- 用户删除 -->
  24. <action name="removeUser" class="com.pc.user.web.action.UserAction" method="removeUser"/>
  25. </package>
  26. </struts>


main.jsp


  
  
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>主页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/saveUser.action"</span>&gt;</span>用户保存<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"${pageContext.request.contextPath}/removeUser.action">用户删除 </a>
  10. </body>
  11. </html>


success.jsp


  
  
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>成功 </title>
  7. </head>
  8. <body>
  9. <h2>执行成功 </h2>
  10. <% System.out.println("执行成功"); %>
  11. </body>
  12. </html>


访问结果

访问Action前,MyInterceptor1拦截了 
保存成功
执行成功
访问Action后,MyInterceptor1拦截了

删除成功
执行成功


PS:可以看出,正如执行流程所示,拦截器在访问Action之前拦截了一次和返回视图之后拦截了一次。

扩展案例:MethodFilterInterceptor拦截器的使用
     MethodFilterInterceptor拦截器,提供了对指定方法集合的拦截和对指定方法集合的放行。
     先看看MethodFilterInterceptor的源码,可以发现该拦截器已经实现了intercept方法,并且提供了一个setIncludeMethods和一个setExcludeMethods来设置拦截方法集和不拦截方法集。并定义了一个doIntercept,提供给子类,作用与intercept方法一样。


  
  
  1. package com.opensymphony.xwork2.interceptor;
  2. import com.opensymphony.xwork2.ActionInvocation;
  3. import com.opensymphony.xwork2.util.TextParseUtil;
  4. import com.opensymphony.xwork2.util.logging.Logger;
  5. import com.opensymphony.xwork2.util.logging.LoggerFactory;
  6. import java.util.Collections;
  7. import java.util.Set;
  8. public abstract class MethodFilterInterceptor extends AbstractInterceptor {
  9. protected transient Logger log = LoggerFactory.getLogger(getClass());
  10. protected Set<String> excludeMethods = Collections.emptySet();
  11. protected Set<String> includeMethods = Collections.emptySet();
  12. public void setExcludeMethods(String excludeMethods) {
  13. this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
  14. }
  15. public Set<String> getExcludeMethodsSet() {
  16. return excludeMethods;
  17. }
  18. public void setIncludeMethods(String includeMethods) {
  19. this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
  20. }
  21. public Set<String> getIncludeMethodsSet() {
  22. return includeMethods;
  23. }
  24. @Override
  25. public String intercept(ActionInvocation invocation) throws Exception {
  26. if (applyInterceptor(invocation)) {
  27. return doIntercept(invocation);
  28. }
  29. return invocation.invoke();
  30. }
  31. protected boolean applyInterceptor(ActionInvocation invocation) {
  32. String method = invocation.getProxy().getMethod();
  33. // ValidationInterceptor
  34. boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
  35. if (log.isDebugEnabled()) {
  36. if (!applyMethod) {
  37. log.debug( "Skipping Interceptor... Method [" + method + "] found in exclude list.");
  38. }
  39. }
  40. return applyMethod;
  41. }
  42. protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
  43. }


案例


  
  
  1. package com.pc.user.web.action;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.ActionSupport;
  4. /
  5. * 用户Action
  6. @author Switch
  7. * @data 2016年11月20日
  8. * @version V1.0
  9. /
  10. public class UserAction extends ActionSupport {
  11. private static final long serialVersionUID = 366851530423407749L;
  12. /
  13. 模拟登陆
  14. @return
  15. /
  16. public String login() {
  17. ActionContext.getContext().getSession().put( "loginUser", "switch");
  18. System.out.println( "登陆成功");
  19. return "main";
  20. }
  21. /
  22. 模拟保存用户
  23. @return
  24. /
  25. public String saveUser() {
  26. System.out.println( "保存成功");
  27. return SUCCESS;
  28. }
  29. /
  30. 模拟删除用户
  31. @return
  32. /
  33. public String removeUser() {
  34. System.out.println( "删除成功");
  35. return SUCCESS;
  36. }
  37. }


  
  
  1. package com.pc.user.web.interceptor;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.ActionInvocation;
  4. import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
  5. /*
  6. * 权限过滤器,实现登录验证
  7. * 通过实现方法过滤拦截器实现
  8. @author Switch
  9. * @data 2016年11月20日
  10. * @version V1.0
  11. */
  12. public class PrivilegeInterceptor extends MethodFilterInterceptor {
  13. private static final long serialVersionUID = - 623800184006159480L;
  14. @Override
  15. protected String doIntercept(ActionInvocation invocation) throws Exception {
  16. // 判断session中是否有用户数据
  17. ActionContext context = ActionContext.getContext();
  18. Object loginUser = context.getSession().get( "loginUser");
  19. // 用户不存在,则返回登录界面
  20. if (loginUser == null) {
  21. return "login";
  22. }
  23. // 放行
  24. return invocation.invoke();
  25. }
  26. }


struts.xml



  
  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. <struts>
  5. <constant name="struts.devMode" value="true"/>
  6. <!-- 定义一些公共的配置:针对当前web工程的 -->
  7. <package name="myDefaultPackage" extends="struts-default" abstract="true">
  8. <interceptors>
  9. <!-- 声明权限拦截器 -->
  10. <interceptor name="privilegeInterceptor1" class="com.pc.user.web.interceptor.PrivilegeInterceptor"/>
  11. <!-- 定义一个拦截器栈:包含权限拦截器和默认拦截器栈 -->
  12. <interceptor-stack name="myDefaultStack">
  13. <interceptor-ref name="privilegeInterceptor1">
  14. <!-- 给拦截器注入参数:告知拦截器拦截哪些或者是排除哪些方法。挑少的写
  15. 传入参数的name是找MethodFilterInterceptor中setXXXX方法后面的部分。
  16. 传入参数的值写的是动作方法名称,如果是多个方法,以逗号分隔。
  17. <param name="excludeMethods">login</param> -->
  18. </interceptor-ref>
  19. <interceptor-ref name="defaultStack"/>
  20. </interceptor-stack>
  21. </interceptors>
  22. <!-- 定义默认拦截器栈:把myDefaultStack声明为默认拦截器栈 -->
  23. <default-interceptor-ref name="myDefaultStack" />
  24. </package>
  25. <package name="pack1" extends="myDefaultPackage" namespace="">
  26. <!-- 全局结果视图 -->
  27. <global-results>
  28. <result name="success" type="dispatcher">/success.jsp </result>
  29. <result name="login" type="redirect">/login.jsp </result>
  30. </global-results>
  31. <!-- 用户登录 -->
  32. <action name="login" class="com.pc.user.web.action.UserAction" method="login">
  33. <!-- 转发到主页 -->
  34. <result name="main" type="dispatcher">/main.jsp </result>
  35. <interceptor-ref name="myDefaultStack">
  36. <!-- 指定给过滤器栈中哪个过滤器设置参数 -->
  37. <param name="privilegeInterceptor1.excludeMethods">login </param>
  38. </interceptor-ref>
  39. </action>
  40. <!-- 用户保存 -->
  41. <action name="saveUser" class="com.pc.user.web.action.UserAction" method="saveUser"/>
  42. <!-- 用户删除 -->
  43. <action name="removeUser" class="com.pc.user.web.action.UserAction" method="removeUser"/>
  44. </package>
  45. </struts>


login.jsp


  
  
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>登录页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/login.action">用户登录 </a>
  10. </body>
  11. </html>


main.jsp



  
  
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>主页 </title>
  7. </head>
  8. <body>
  9. <a href="${pageContext.request.contextPath}/saveUser.action"</span>&gt;</span>用户保存<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"${pageContext.request.contextPath}/removeUser.action">用户删除 </a>
  10. </body>
  11. </html>


success.jsp


  
  
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>成功 </title>
  7. </head>
  8. <body>
  9. <h2>执行成功 </h2>
  10. <% System.out.println("执行成功"); %>
  11. </body>
  12. </html>





猜你喜欢

转载自blog.csdn.net/qecode/article/details/80923046