一、为什么需要拦截器
1.早期MVC框架将一些通用操作写死在核心控制器中,致使框架灵活性不足、可扩展性降低
2.Struts 2将核心功能放到多个拦截器中实现,拦截器可自由选择和组合,增强了灵活性,有利于系统的解耦
二、什么是拦截器
1.Struts 2大多数核心功能是通过拦截器实现的,每个拦截器完成某项功能
2.拦截器方法在Action执行之前或者之后执行
三、拦截器栈
1.从结构上看,拦截器栈相当于多个拦截器的组合
2.在功能上看,拦截器栈也是拦截器
四、拦截器的原理
拦截器与过滤器原理很相似,以链式执行
HttpServletRequest HttpServletResponse
|① |11
核心控制器 核心控制器
|② |⑩
Interceptor1 Interceptor1
|③ |⑨
Interceptor2 Interceptor2
|④ |⑧
Interceptor3 Interceptor3
|⑤ ⑥ |⑦
Action ----> Result
首先执行Action配置的拦截器,在Action和Result执行之后,拦截器再
一次执行(与先前调用相反的顺序),在此链式的执行过程中,任何一个
拦截器进了可以直接返回,从而终止余下的拦截器、Action及Result的执行
拦截器的执行可看作递归过程:
框架通过第一次调用ActionInvocation的invoke()方法开始这一过程,ActionInvocation通过调用拦截器的intercept()方法把控制转交给为Action配置的第一个拦截器。最重要的是intercept()把ActionInvocation实例看作参数,在拦截器的处理过程中,它会调用ActionInvocation对象上的invoke()方法来继续调用后续拦截器。
拦截器有一个三阶段的、有条件的执行周期:
1.做一些Action执行前的预处理: 拦截器可以准备、过滤、改变或者操作任何可以访问的数据,包括Action。
2.调用ActionInvocation的invoke()方法将控制转交给后续的拦截器或者返回结果字符串终止执行:如果拦截器决定请求的处理不应该继续,可以不调用invoke()方法,而是直接返回一个控制字符串。通过这种方式,可以停止后续的执行,并且决定哪个结果呈现给客户端。
3.做一些Action执行后的处理:此时拦截器依然可以改变只可以访问的对象和数据,只是此时框架已经选择了一个结果呈现给客户端了。
代码:
public class MyTimerInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//1.执行Action之前的工作:获取开始时间
long statTime = System.currentTimeMillis();
System.out.println("执行Action之前的工作,开始时间"+statTime);
//2.执行后续拦截器或Action
String result = invocation.invoke();
//3.执行Action之后的工作:计算并输出执行时间
long endTime = System.currentTimeMillis();
long execTime = endTime - statTime;
System.out.println("执行Action后的,结束时间"+endTime);
System.out.println("总共用时"+execTime);
//返回结果字符串
return result;
}
}
拦截器的配置:
1.使用步骤:
1)通过<interceptor.../>元素定义拦截器。
2)通过<interceptor.../>元素来使用拦截器
在struts.xml配置文件
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<!-- 定义拦截器 -->
<interceptor name="myTimer" class="com.jbit.intercepotr.MyTimerInterceptor"></interceptor>
</interceptor>
</interceptors>
<action name="action" class="com.jbit.intercepotr.MyTimerAction">
<result>index.jsp</result>
<interceptor-ref name="myTimer"></interceptor-ref>
<!-- 定义默认的拦截器引用 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
下面使用拦截器栈
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<!-- 定义拦截器 -->
<interceptor name="myTimer" class="com.jbit.intercepotr.MyTimerInterceptor"></interceptor>
<interceptor name="myTimer2" class="com.jbit.intercepotr.MyTimerAction2"></interceptor>
<!-- 定义拦截器栈 -->
<interceptor-stack name="stackName">
<!-- 指定引用的拦截 -->
<interceptor-ref name="myTimer"></interceptor-ref>
<interceptor-ref name="myTimer2"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器引用 -->
<default-interceptor-ref name="defaultStack"></default-interceptor-ref>
<action name="action" class="com.jbit.intercepotr.MyTimerAction">
<result>index.jsp</result>
<interceptor-ref name="stackName"></interceptor-ref>
</action>
</package>