Struts2 拦截器

 

Filter、Interceptor都是AOP思想的体现。

Filter(过滤器)会拦截所有的请求,对html、jsp、Servlet等资源的请求都会被拦截。

Interceptor(拦截器)只拦截对Action的请求,且可以实现细粒化拦截,可以只拦截Action中的部分方法。

 

 

 

 

 

 

 

Filter、Interceptor的执行顺序都是:去的时候依次执行1,2,3,回来的时候就依次执行3,2,1。

因为是在1里面放行,调用2,在2里面放行,调用3,3里面放行调用Action|Servlet|JSP|html,得到响应对象,

响应对象返还给3,3对响应对象进行处理,返回给2,2对响应对象进行处理,返回给1,1对响应对象进行处理,返回给服务器,服务器返回给浏览器。

相当于递归调用。

 

注意是先调用JSP,由JSP组成响应,再由拦截器对响应进行进一步处理。

拦截器能拦截请求,也能拦截响应。

 

 


 

 

 

拦截器的配置

<struts>
    <package name="action" namespace="/action" extends="struts-default">
        <interceptors>
            <interceptor name="" class=""></interceptor>
            
            <interceptor-stack name="">
                <interceptor-ref name=""></interceptor-ref>
                <interceptor-ref name=""></interceptor-ref>
                <interceptor-ref name=""></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        
        <default-interceptor-ref name=""></default-interceptor-ref>

        
        <action name="" class="">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name=""></interceptor-ref>

            <result name=""></result>
            <result name=""></result>
        </action>

    </package>

</struts>

 

在<interceptors>中注册拦截器、拦截器栈,注册之后就可以通过name来引用拦截器、拦截器栈。可以用拦截器栈来组合一组拦截器。

<default-interceptor-ref name=""></default-interceptor-ref>配置默认引用的拦截器、拦截器栈,此配置会覆盖struts-default.xml中的默认拦截器配置。如果我们配置了拦截器、拦截器栈的引用,就不会再自动调用默认的;如果我们没有配置拦截器、拦截器栈的引用,会自动调用默认的。

<interceptors>、<default-interceptor-ref>均只能作为<package>的子元素来配置。

 

在<action>中使用<interceptor-ref>来引用拦截器、拦截器栈,可同时引用多个,默认拦截器栈中有很多通用处理,一般都要引用。

<interceptor-ref>只能作为<action>的子元素来配置。

去的时候,按照引用的先后顺序依次调用拦截器,回来的时候,调用顺序相反。

 

 

struts-default.xml中的默认拦截器配置:

<interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

<default-interceptor-ref name="defaultStack"/>

servletConfig拦截器用于获取原生的Servlet API。

modelDriven用于模型驱动获取参数。

fileUpload用于文件上传。

params用于封装请求参数。

.........

默认的拦截器(栈)有大量的通用操作,一般都要引用。如果不引用默认的拦截器(栈),struts2的很多功能都用不了。

 

 

拦截器是Struts2的核心,完成了Struts2的大部分工作,比如解析请求参数、将请求参数赋给Action的成员变量,数据校验,文件上传等。

Struts2的拦截器是可插拔式设计,要使用某个拦截器,在配置文件中引入即可,不使用时在配置文件中删除即可。

 

 

 


 

 

 

自定义拦截器类

Interceptor本质是一个Java类,新建一个Java类即可。有3种方式:

  • 实现Interceptor接口       需实现里面所有的抽象方法
  • 实现AbstractInterceptor抽象类    这个类是Interceptor的子类,为其它方法提供了空实现,只有核心方法intercept()是抽象的。实现intercept()方法即可。
  • 实现MethodFilterInterceptor抽象类    这个类是AbstractInterceptor的(抽象)子类,可以只拦截Action中的部分方法。需要实现doIntercept()方法。

 

 

Interceptor接口:

public interface Interceptor extends Serializable {
    void destroy();

    void init();

    String intercept(ActionInvocation var1) throws Exception;
}

在init()中做初始化,在destroy中清理善后,intercept()是核心方法,用于拦截处理。

 

 

使用AbstractInterceptor:

public class MyInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        //去的时候做一些处理
        System.out.println("before");
        
        //放行
        String result = actionInvocation.invoke();
        
        //回来的时候做一些处理
        System.out.println("after");
        
        return result;
    }
}

需要返回String,如果需要在回来的时候做一些处理,要将return放到最后。

返回的String就是action返回的那个String,如果不想进行后续处理,不调用 actionInvocation.invoke() ,直接返回一个String(逻辑视图名)即可。

如果不调用JSP来显示,可以 return null; 。

 

 

 

 

使用MethodFilterInterceptor拦截action中的部分方法:

public class MyInterceptor extends MethodFilterInterceptor {
    @Override
    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        //去的时候做一些处理
        System.out.println("before");
        
        //放行
        String result = actionInvocation.invoke();
        
        //回来的时候做一些处理
        System.out.println("after");
        
        return result;
    }
}

 

 

Action中有多个处理业务的方法:

public class MyAction{
    public String add(){
        System.out.println("add");
        return "ok";
    }

    public String update(){
        System.out.println("update");
        return "ok";
    }

    public String delete(){
        System.out.println("delete");
        return "ok";
    }
}

 

 

拦截器配置:

<struts>
    <package name="action" namespace="/" extends="struts-default">
        <interceptors>
            <interceptor name="myInterceptor" class="interceptor.MyInterceptor">
                <param name="includeMethods">add,delete</param>
            </interceptor>
        </interceptors>
<action name="MyAction_*" class="action.MyAction" method="{1}"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="myInterceptor"></interceptor-ref> <result name="ok">/index.jsp</result> <allowed-methods>add,update,delete</allowed-methods> </action> </package> </struts>

MethodFilterInterceptor常与Action动态方法调用搭配使用。

 

 

注册拦截器时,需指定要拦截的方法|不拦截的方法:

<interceptor name="myInterceptor" class="interceptor.MyInterceptor">
         <param name="includeMethods">add,delete</param>
         <param name="excludeMethods">update</param>
</interceptor>

includeMethods指定此拦截器要拦截的方法,excludeMehtods指定不拦截的方法,这2个参数不能一起使用。指定了其中一个,剩下的方法都是另一个的。

要调用的方法是includeMethods中的方法时,才会使用此拦截器进行拦截,否则不使用此拦截器进行拦截。

此例中,访问MyAction_add、MyAcion_delete时,均会调用此拦截器;访问MyAction_update时,不会调用此拦截器。

 

处理机制:请求传递给此拦截器,此拦截器检查要调用的方法是否是includeMethods中的方法,是就处理,不是就直接放行。

 

 

 


 

 

Interceptor的生命周期

Interceptor在部署|启动WebApp时就创建实例,调用init()进行初始化。

从Tomcat中移除当前WebApp时,Interceptor实例随着WebApp的销毁而销毁,会自动调用destroy()。

 

Interceptor是单例的,一个Interceptor在Tomcat中只有一个实例。

在Interceptor的生命周期中,init()、destroy()均只调用1次。每次拦截请求都会调用核心拦截方法。

 

Action是多例的,每次处理请求都会创建一个新的Action实例。

处理完业务,调用JSP之后,此Action的生命周期才结束。

注意是执行要调用的JSP之后,Action实例才销毁。就是说在执行JSP时,此Action的ValueStack还在,仍可以从中取出数据。

 

 

 


 

 

 

 

使用Interceptor实现权限校验

用户登录,登录成功后可执行相关操作,直接执行用户操作,不再检查用户权限、信息,这是不行的。

比如用户可以直接在地址栏输入URL,转到操作页面进行操作,跳过用户登录。

 

可以使用拦截器拦截用户请求,检查用户权限:

从session中获取用户信息、权限,如果满足条件,就放行,如果未登录、权限不够,就转发到对应的登录页面、提示页面。

在用户登录成功时,将用户信息、权限放到session中。

 

可使用MethodFilterInterceptor只拦截Action中需要检查权限的某些方法。

 

posted @ 2019-09-08 18:17 chenhongyong 阅读(...) 评论(...) 编辑 收藏