struts2学习笔记(六)—— 拦截器

一、拦截器概述

  拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前进行拦截,然后在之前或之后加入某些操作。拦截器是AOP的一种实现策略。

  在Webwork的中文文档的解释为:拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

  谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

二、拦截器的实现原理

  大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。事实上,我们之所以能够如此灵活地使用拦截器,完全归功于“动态代理”的使用。动态代理是代理对象根据客户的需求做出不同的处理。对于客户来说,只要知道一个代理对象就行了。那Struts2中,拦截器是如何通过动态代理被调用的呢? 当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute()或指定的方法,并在 struts.xml中查找与该Action对应的拦截器。如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截 器则执行Action的方法。其中系统对于拦截器的调用,是通过ActionInvocation来实现的。

  Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

三、自定义拦截器

3.1 实现Interceptor接口

public class MyInterceptor implements Interceptor {

    @Override
    // 初始化方法
    public void init() {
    }

    @Override
    // 拦截方法
    public String intercept(ActionInvocation arg0) throws Exception {
        return null;
    }
    
    @Override
    // 销毁方法
    public void destroy() {
    }
}

  Interceptor接口提供了三个方法,其具体介绍如下

  • void init():该方法在拦截器被创建后会立即调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。
  • void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内也只被调用一次。
  • String interceptor(ActionInvocation invocation):该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求, 该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。

3.2 继承AbstractInterceptor

// 帮我们空实现了init和destory方法,如果我们不需要实现这两个方法,就可以只实现intercept方法
public class MyInterceptor extends AbstractInterceptor{

    @Override
    public String intercept(ActionInvocation arg0) throws Exception {
        return null;
    }
}

  抽象类AbstractInterceptor已经实现了Interceptor接口的所有方法,一般情况下,只需继承AbstractInterceptor类,实现interceptor()方法就可以创建自定义拦截器。
  只有当自定义的拦截器需要打开系统资源时,才需要覆盖AbstractInterceptor类的init()方法和destroy()方法。与实现Interceptor接口相比,继承AbstractInterceptor类的方法更为简单

3.3 继承MethodFilterInterceptor

// 功能:定制拦截器拦截的方法
// 定制哪些方法需要拦截,哪些方法不需要拦截
public class MyInterceptor extends MethodFilterInterceptor{

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        // 前处理
        System.out.println("MyInterceptor的前处理");
        // 放行
        String result = invocation.invoke();
        // 后处理
        System.out.println("MyInterceptor的后处理");
        return result;
        // 不放行,直接跳转到一个结果页面(不执行后续的拦截器以及Action,直接交给Result处理结果.进行页面跳转)
        // return "success";
    }

}

  MethodFilterInterceptor是AbstractInterceptor的子类,该类中提供了两个属性,可以告知拦截器对哪些方法进行拦截或者对哪些方法排除。这种方法在开发中最常用

  

四、配置拦截器

<package name="interceptor" namespace="/" extends="struts-default">
    <interceptors>
        <!-- 1.注册拦截器 -->
        <interceptor name="myInterceptor" class="cn.itcast.interceptor.MyInterceptor"></interceptor>
        <!-- 2.注册拦截器栈 -->
        <interceptor-stack name="myStack">
            <!-- 引入自定义拦截器(建议放在20个拦截器之前) -->
            <interceptor-ref name="myInterceptor">
                <!-- 指定哪些方法不拦截 
                <param name="excludeMethods">add,delete</param> -->
                <!-- 指定哪些方法要拦截 -->
                <param name="includeMethods">add,delete</param>
            </interceptor-ref>
            <!-- 引入默认的拦截器栈(20个) -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </interceptor-stack>
    </interceptors>
    <!-- 3.指定包中的默认拦截器栈 -->
    <default-interceptor-ref name="myStack"></default-interceptor-ref>
    
    <action name="Demo1Action_*" class="cn.itcast.action.Demo1Action" method="{1}">
        <result name="success" type="dispatcher">/index.jsp</result>
    </action>
</package>
posted @ 2019-01-16 16:14  yi0123  阅读(207)  评论(0编辑  收藏  举报