拦截器的整个过程java
程序是在执行Action以前调用的拦截器,整个过程是这样子的spring
这里面注意两个问题:编程
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); try { Configuration config = configurationManager.getConfiguration(); ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
这个字段就是"struts.valueStack"
// if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { } else { proxy.execute(); } } catch (ConfigurationException e) { }
就看里面标记的这几句,这个方法的做用设置好valueStack,而后放到request范围里服务器
也就是说经过request能够获得valueStack对象;session
so,在视图上拿valueStack对象的方式就有如下两种:架构
1.request.getAttribute()app
2.ongl: #request.structs.valueStackjsp
第二个是循环Interceptor的问题,每个Interceptor里面其实都调用了invoke方法,this
那么这个调用是怎么实现的呢,spa
如今作一个模拟就明白了
拦截器原理模拟
使用最简单的java工程作实验
而后定义一个Action,表示最后要执行的东东
public class Action {
public void execute() { System.out.println("execute!"); } }
而后最重要的是定义一个ActionInvocation
import java.util.ArrayList; import java.util.List; public class ActionInvocation { List<Interceptor> interceptors = new ArrayList<Interceptor>(); int index = -1; Action a = new Action(); public ActionInvocation() { this.interceptors.add(new FirstInterceptor()); this.interceptors.add(new SecondInterceptor()); }
//首先遍历每个拦截器,当遍历完了以后,执行Action的方法 public void invoke() { index ++; if(index >= this.interceptors.size()) { a.execute(); }else { this.interceptors.get(index).intercept(this); } } }
先定义一个接口,至关于拦截器
public interface Interceptor { public void intercept(ActionInvocation invocation) ; }
而后两个类实现这个接口
public class FirstInterceptor implements Interceptor { public void intercept(ActionInvocation invocation) { System.out.println(1);
//在里面又返回调用ActionInvocation 的Invoke方法 invocation.invoke(); System.out.println(-1); } }
public class SecondInterceptor implements Interceptor { public void intercept(ActionInvocation invocation) { System.out.println(2); invocation.invoke(); System.out.println(-2); } }
定义主方法
public class Main { public static void main(String[] args) { new ActionInvocation().invoke(); } }
最后的结果是
1
2
execute!
-2
-1
这里面最关键的地方就是转来转去用的都是同一个ActionInvocation 对象
流程大概是:
实线表示直接调用,虚线表示方法返回
上图是完整的调用过程
由于ActionInvocation调用Second是在First内部,只是转折了一下,因此能够理解为First调用了Second
经过Struct官方的图来理解整个过程
最主要的思想是在执行Action以前拦一下,在执行以后拦一下
从这个图中,也能够理解什么叫作AOP,面向切面编程
原本有没有拦截器Struct方法都能执行
可是忽然冒出一个拦截器有种在执行以前切上一刀的感受
拦截器的有点是可插入,可抽回
拦截器能够用在敏感字符处理,在提交的数据进入服务器的时候,首先检查数据是否是有敏感字符
还能够用在权限上面
咱们想一下若是没有拦截器怎么作权限
有两种方式:
一个是在Action类中的exection方法里面进行判断
一个是在Jsp的头的session里面进行判断
这样作是要在每个Action和JSP里面都要写的啊
固然权限判断如今有很好的spring security
定义本身的Struct拦截器
这个其实就是重复形成轮子的过程,只要看看别人的轮子是怎么造出来的就能够了。
首先:定义一个MyInterceptor类
package com.bjsxt.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class MyInterceptor implements Interceptor { public void destroy() { // TODO Auto-generated method stub } public void init() { // TODO Auto-generated method stub } public String intercept(ActionInvocation invocation) throws Exception { long start = System.currentTimeMillis(); String r = invocation.invoke(); long end = System.currentTimeMillis(); System.out.println("action time = " + (end - start)); return r; } }
而后要把这个拦截器加到配置里面
在Struct里面,默认拦截器都是放在/struts-default.xml 里面,固然咱们不能改人家的代码。
修改Struct.xml
<package name="test" namespace="/" extends="struts-default">
首先声明这个拦截器
<interceptors> <interceptor name="my" class="com.bjsxt.interceptor.MyInterceptor"></interceptor> </interceptors> <action name="test" class="com.bjsxt.action.TestAction"> <result>/test.jsp</result> <interceptor-ref name="my"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action> </package>
在实际开发过程当中,自定义拦截器其实是不多不多用到的。一方面,Struct已经为咱们写出来不少拦截器,另外一方面,一旦咱们自定义了拦截器,那么咱们的代码就和Struct绑定上了,之后若是再换成其余架构基本上是没法实现的。