码迷,mamicode.com
首页 > 其他好文 > 详细

struts2(六)拦截器机制

时间:2016-05-13 02:57:09      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:


拦截器简述

拦截器是一组动态拦截Action调用的对象。拦截器的处理代码可以定义在action执行前或者执行后。同时,拦截器能够拦截一个Action的执行。拦截器可以将一些通用功能封装成可重用形式以供一个Action或多个 Actions使用。

技术分享

拦截器必须是无状态的,原因是Struts 2不能保证为每一个请求或者Action创建一个实例,所以如果拦截器带有状态,会引发并发问题。不要使用在API提供的ActionInvocation之外的任何东西。

在概念上,interceptors相近于Servlet 的filters或者JDKs的Proxy类。可以把struts2理解成一个空容器,而大量的内建拦截器完成该框架的大部分操作。比如,params拦截器负责解析HTTP请求的参数,并设置Action的属性;servlet-config拦截器直接将HTTP请求中的HttpServletRequest实例和HttpServletResponse实例传给Action;fileUpload拦截器负责解析请求参数中的文件域,并将一个文件域设置为Action的三个属性等等。这些通用操作是通过struts2的内建拦截器完成的。

struts2拦截器是可插拔式的,如果需要使用某个拦截器,只需要在配置文件中应用该拦截器即可,如果不使用该拦截器只需要在配置文件中取消该拦截器,不用重新部署应用。

struts2拦截器由struts-default.xml、struts.xml等配置文件进行管理,开发者可以很容易地扩展自己的拦截器。

如前面所说开发中存在一些通用逻辑,如解析请求参数、类型转换、将请求参数封装成DTO(Data Transfer Object)、执行输入校验、解析文件上传表单中的文件域、防止表单的多次提交等。struts2把大部分核心控制器需要完成的工作功能分开定义,每个拦截器完成一个功能。这些拦截器可以自由选择,灵活组合(甚至不用struts2的任何拦截器),需要哪些拦截器只需在struts.xml文件中指定使用该拦截器即可。

在struts.xml文件中配置Action时,在package里继承struts-default包,包内的大量通用功能的拦截器就会起作用。

<package name="default" extends="struts-default">
   <interceptors>
       <interceptor name="timer" class=".."/>
       <interceptor name="logger" class=".."/>
   </interceptors>

   <action name="login"
      class="tutorial.Login">
        <interceptor-ref name="timer"/>
        <interceptor-ref name="logger"/>
         <result name="input">login.jsp</result>
         <result name="success"
            type="redirectAction">/secure/home</result>
   </action>
</package>

在web.xml文件中定义核心Filter。

<!-- 定义struts2核心Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <!-- 让struts2的核心Filter拦截所有action请求 -->
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

当StrutsPrepareAndExecuteFilter拦截到用户请求后,大量拦截器将会对用户请求进行处理,然后才会调用用户开发的Action实例的方法处理请求。拦截器与Action之间的关系如下图所示。

技术分享

struts2内建的拦截器

struts2内建了大量的拦截器,这些拦截器以name-class对的形式配置在struts-default.xml文件中,其中name是拦截器的名字,就是以后使用该拦截器的唯一表示;class指定了该拦截器的实现类,程序定义的package继承了struts2的默认struts-default包,就可以使用包内定义的拦截器,不用自己定义拦截器。

技术分享

技术分享

技术分享

自定义拦截器

内建拦截器实现了struts2大部分功能,大部分Web应用的通用功能,都可以通过直接使用这些内建拦截器完成,但有一些系统逻辑相关的通用相关功能,要通过自定义拦截器来实现。

Interceptor接口

开发自定义拦截器类,要实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口的定义代码如下。

public interface Interceptor extends Serializable {
    //销毁该拦截器之前的回调方法
    void destroy();
    //初始化该拦截器的回调方法
    void init();  
    //拦截器实现拦截的逻辑方法
    String intercept(ActionInvocation invocation) throws Exception;

}


init()方法在该拦截器被实例化之后,执行拦截之前被回调。每个拦截器的init()方法只执行一次。所以该方法体主要用于初始化资源,例如数据库连接等。

destroy()对应于init()方法,在拦截器实例被销毁之前,系统将回调该拦截器的destroy方法,用于销毁在init()方法里打开的资源。

inercept(ActionInvocation invocation)方法是用户需要实现的拦截动作,像Action的execute方法,intercept方法返回一个字符串作为逻辑视图。如果该方法直接返回一个字符串,系统会跳转到该逻辑视图对应的实际 视图资源,不会调用被拦截的Action。该方法的ActionInvocation参数包含了被拦截的Action引用,可以通过调用该参数的invoke方法,将控制权转给下一个拦截器,或者转给Action的execute方法。

AbstractInterceptor类

AbstractInterceptor类实现了Interceptor接口。

技术分享

技术分享

AbstractInterceptor类提供了init()和destory()方法的空实现,如果实现的拦截器不需要打开资源则可以无需实现这两个方法。

技术分享

定义和使用拦截器

自定义一个拦截器需要三步:

1. 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。

2. 在strutx.xml中注册上一步中定义的拦截器。

3. 在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。

自定义拦截器

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import java.util.*;
import com.afy.app.action.*;

public class SimpleInterceptor extends AbstractInterceptor{
    // 简单拦截器的名字
    private String name;
    // 为该简单拦截器设置名字的setter方法
    public void setName(String name){
        this.name = name;
    }
    public String intercept(ActionInvocation invocation) throws Exception{
        // 取得被拦截的Action实例
        LoginAction action = (LoginAction)invocation.getAction();
        // 打印执行开始的时间
        System.out.println(name + " 拦截器的动作---------" +
            "开始执行登录Action的时间为:" + new Date());
        // 取得开始执行Action的时间
        long start = System.currentTimeMillis();
        // 执行该拦截器的后一个拦截器
        // 如果该拦截器后没有其他拦截器,则直接执行Action的被拦截方法
        String result = invocation.invoke();
        // 打印执行结束的时间
        System.out.println(name + " 拦截器的动作-------" + "执行完登录Action的时间为:" + new Date());
        long end = System.currentTimeMillis();
        System.out.println(name + " 拦截器的动作---------" + "执行完该Action的时间为" + (end - start) + "毫秒");
        return result;
    }
}

在strutx.xml中注册上一步中定义的拦截器,在需要使用的Action中引用上述定义的拦截器。

<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <!-- 通过常量配置该应用所使用的字符集-->
    <constant name="struts.i18n.encoding" value="GBK"/>
    <!-- 配置本系统所使用的包 -->
    <package name="lee" extends="struts-default">
        <!-- 应用所需使用的拦截器都在该元素下配置 -->
        <interceptors>
            <!-- 配置mySimple拦截器 -->
            <interceptor name="mySimple"
            class="org.crazyit.app.interceptor.SimpleInterceptor">
                <!-- 为拦截器指定参数值 -->
                <param name="name">简单拦截器</param>
            </interceptor>
        </interceptors>

        <action name="login" class="org.crazyit.app.action.LoginAction">
            <result name="error">/WEB-INF/content/error.jsp</result>
            <result>/WEB-INF/content/welcome.jsp</result> 
            <!-- 配置系统的默认拦截器 -->
            <interceptor-ref name="defaultStack"/>
            <!-- 应用自定义的mySimple拦截器 -->
            <interceptor-ref name="mySimple">
                <param name="name">改名后的拦截器</param>
            </interceptor-ref>
        </action>
        <action name="*">
            <result>/WEB-INF/content/{1}.jsp</result>
        </action>
    </package>
</struts>


拦截器的实现原理

大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。

技术分享

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

与过滤器的区别

过滤器可以简单理解为“取你所想取”,忽视掉那些你不想要的东西;拦截器可以简单理解为“拒你所想拒”,关心你想要拒绝掉哪些东西,比如一个BBS论坛上拦截掉敏感词汇。

1. 拦截器是基于java反射机制的,而过滤器是基于函数回调的。

2. 过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。

3. 拦截器只对action起作用,而过滤器几乎可以对所有请求起作用。

4. 拦截器可以访问action上下文、值栈里的对象,而过滤器不能。

5. 在action的生命周期里,拦截器可以多起调用,而过滤器只能在容器初始化时调用一次。

struts2(六)拦截器机制

标签:

原文地址:http://blog.csdn.net/csdnyoyo/article/details/51339784

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!