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绑定上了,以后如果再换成其他架构基本上是无法实现的。

 

posted on 2014-12-12 21:26  飞鸟快跑  阅读(1042)  评论(0编辑  收藏  举报