Struct2 拦截器
拦截器的整个过程
程序是在执行Action之前调用的拦截器,整个过程是这样子的
这里面注意两个问题:
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对象;
so,在视图上拿valueStack对象的方式就有以下两种:
1.request.getAttribute()
2.ongl: #request.structs.valueStack
第二个是循环Interceptor的问题,每一个Interceptor里面其实都调用了invoke方法,
那么这个调用是怎么实现的呢,
现在做一个模拟就明白了
拦截器原理模拟
使用最简单的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绑定上了,以后如果再换成其他架构基本上是无法实现的。