Struts2拦截器工作原理
拦截器围绕着 Action和 Result的执行而执行。 Struts2拦截器的工作方式如图10.2所示。从上图中可以看出, Struts2拦截器的实现原理和 Servlet Filter的实现原理差不多,以链式执行对真正要执行的方法( execute()进行拦截。首先执行 Action配置的拦截器,在 Action和 Result执行之后,拦截器再一次执行(与先前调用相反的顺序),在此链式的执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器、 Action及 Result的执行。
当 Actioninvocation的moke(方法被调用时,开始执行 Action配置的第一个拦截器,拦截器做出相应处理后会再次调用 Actioninvocation的 invoke()方法, Actioninvocation对象负责跟踪执行过程的状态,并且把控制权交给合适的拦截器。 Actioninvocation通过调用拦截器的 Intercept()方法将控制权转交给拦截器。因此,拦截器的执行过程可以看作一个递归的过程,后续拦截器继续执行,直到最后一个拦截器, invoke()方法会执行 Action。
拦截器有一个三阶段的、有条件的执行周期,如下所示:
(1)做一些 Action执行前的预处理。拦截器可以准备、过滤、改变或者操作任何可以访问的数据,包括 Action。
(2)调用 Actioninvocation的 evoke()方法将控制权转交给后续的拦截器或者返回结果字符串终止执行。如果拦截器决定请求的处理不应该继续,可以不调用 invoke()方法,而是直接返回一个控制字符串。通过这种方式,可以停止后续的执行,并且决定将哪个结果呈现给客户端。
(3)做一些 Action执行后的处理。此时拦截器依然可以改变可以访问的对象和数据,只是此时框架已经选择了一个结果呈现给客户端了
自定义拦截器例子:
(1)自定义拦截器类
1 package cn.test.interceptor; 2 3 import com.opensymphony.xwork2.ActionInvocation; 4 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 5 6 public class MyTimeIntercepter extends AbstractInterceptor { 7 8 private static final long serialVersionUID = 1L; 9 10 @Override 11 public String intercept(ActionInvocation invocation) throws Exception { 12 // 1.执行Action之前的工作:获取开始执行时间 13 long startTime = System.currentTimeMillis(); 14 System.out.println("执行Action之前的工作,开始时间:" + startTime); 15 // 2.执行后续拦截器或Action 16 String result = invocation.invoke(); 17 // 1.执行Action之后的工作:计算并输出执行时间 18 long endTime = System.currentTimeMillis(); 19 20 System.out.println("执行Action之后的工作,结束时间:" + endTime); 21 System.out.println("总共用时:" + (endTime - startTime)); 22 return result; 23 } 24 25 }
获得结果字符串之后, My Timer Interceptor拦截器记录了执行的用时,在控制台进行了输出。此时拦截器可以使用结果字符串做一些操作,但是在这里不能停止或者改变响应。对于
My T imer Interceptor拦截器而言,它不关心结果,因此它不查看返回的结果字符串。
1 <?xml version="1.0" encoding="UTF-8"?> 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 <package name="default" namespace="/" extends="struts-default"> 7 <!-- 配置默认的行为 --> 8 <default-action-ref name="defaultAction"></default-action-ref> 9 <!-- 配置默认action --> 10 <action name="defaultAction"> 11 <result type="redirect">/error.jsp</result> 12 </action> 13 </package> 14 15 <!-- 拦截器配置 --> 16 <package name="intercepter" namespace="/" extends="struts-default"> 17 <!-- interceptors元素中使用interceptor子元素定义拦截器 --> 18 <interceptors> 19 <!-- interceptor元素name属性:拦截器的名称,class:自定义拦截器类的全限定类名--> 20 <interceptor name="myTime" class="cn.test.interceptor.MyTimeIntercepter"></interceptor> 21 <interceptor-stack name="myTimeStack"> 22 <interceptor-ref name="myTime"></interceptor-ref> <!-- 把自定义的拦截器设置为栈的顶部 --> 23 <interceptor-ref name="defaultStack"></interceptor-ref> <!--调用struts默认的拦截器--> 24 </interceptor-stack> 25 </interceptors> 26 27 <!--浏览器输入http://localhost:8080/strutsstu4/index并访问,会触发拦截器的执行,计算拦截器执行的时间--> 28 <action name="index"> 29 <result >/index.jsp</result> 30 <interceptor-ref name="myTimeStack"></interceptor-ref> <!-- 当访问index这个actio时,让myTimeStack这个拦截器栈去进行拦截 --> 31 </action> 32 </package> 33 34 </struts>
(3)视图页面:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>My JSP 'index.jsp' starting page</title> 7 </head> 8 9 <body> 10 This is index page. <br> 11 </body> 12 </html>
error.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>My JSP 'success.jsp' starting page</title> 6 </head> 7 8 <body> 9 This is error page. <br> 10 </body> 11 </html>
(4)部署并测试
浏览器输入http://localhost:8080/strutsstu4/index并访问,会触发拦截器的执行,控制台打印拦截器执行的时间,页面跳转到index.jsp,如下:
如果访问一个没有对应action的URL,比如 http://localhost:8080/strutsstu4/sss 则执行默认的action,替换调404报错页面
示例代码下载地址 https://github.com/liuch0228/Struts2SSH.git