struts2(六)拦截器机制

拦截器简述

拦截器是一组动态拦截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的生命周期里,拦截器可以多起调用,而过滤器只能在容器初始化时调用一次。

时间: 2024-11-10 14:56:53

struts2(六)拦截器机制的相关文章

Struts2的拦截器

拦截器的作用: 拦截器可以动态地拦截发送到指定Action的请求,通过拦截器机制,可以载Action执行的前后插入某些代码,植入我们的逻辑思维. 拦截器的实现原理: 拦截器通过代理的方式来调用,通过动态代理我们的Action,在Action的执行前后植入我们的拦截代码.这种拦截器的思想就是一种AOP,取得业务处理过程的切面,在特定切面 通过系统自动插入特定方法. Struts2中的拦截器: 在平常的项目中,我们经常需要解析上传表单中的文件域,防止表单多次提交……,这些操作不是所有Action都需

【struts2】拦截器基础

1)拦截器是什么? 拦截器(Interceptor)是Struts2最强大的特性之一,它是一种可以让你在Action执行之前和Result执行之后进行一些功能处理的机制.来回顾一下官方给出的Struts2系统架构图中关于拦截器的部分,如下图所示: 这个图清晰的描述出了拦截器的运行地位,就是用来负责在Action执行之前和Result执行之后处理一些功能的类.也就是说,上图示意了有3个拦截器的类,分别是Interceptor1.Interceptor2和Interceptor3,它们分别执行不同的

谈谈 Struts2 的拦截器

套话 相信很多人都用过 Struts2 了,当然,对 Struts2 的原理也都比较了解.之前在一个项目中就已经用到了,当初的理解也仅仅是局限在应用的层面上,对于更深层次的原理.机制,了解的并不是很多.现在回过头来,再看 Struts2 的拦截器,相比之前的理解,又别有另一番滋味. 理解 Struts2 的拦截器,英文名为 Interceptor ,至于为什么中文要翻译为拦截器,我想这一定是有原因的,肯定不是一拍脑门,就叫拦截器了(它必定有什么含义在里边).从字面的意思,就是在发送请求的时候,有

调查管理系统 -(6)自定义Struts2的拦截器&amp;自定义UserAware接口&amp;Action中模型赋值问题&amp;Hibernate懒加载问题

1.对于一些功能,如我的调查或新建调查等,只有用户登录后才能进行操作,因此必须对用户是否登录进行判断.当用户登录后才能使用相应的功能,如果没有登录则需为用户导航到登录页面让其进行登录.这个功能可以通过自定义Struts2的拦截器来完成. 2.当用户登录之后,由于是将用户的信息保存在session中的.这样当一些Action中需要用到当前登录的用户的信息时需要手动的从session中获取,不太方便,因此我们声明了一个UserAware接口(即用户关注,类似于Struts2中的SessionAwar

struts2中拦截器的简介与配置使用

拦截器是struts2框架的核心,struts2很多的功能都是构建在拦截器基础之上的,它是动态拦截Action调用的对象,提供了一种机制,使得开发者能够在一个Action前后执行需要的代码,可以在一个Action执行前组织他的执行,也能在Action执行后做一些相应的工作.同时他也提供了一种可以提取Action中可重用部分的方式. 拦截器 struts2拦截器是在访问某个Action或它的某个方法 .字段之前或之后实施拦截,struts2拦截器是可插拔的,是AOP的一种实现(AOP是OOP(Ob

struts2 在拦截器进行注入(根据Action是否实现自定义接口)

例如:常常在Action中都需要获取当前登录的User,就需要获取Session,然后从Session获取当前登录的User,因为这些步骤都是重复操作,可以想办法在拦截器中进行实现,可以自定义一个接口,只要你的Action实现了这个接口,就在自定义拦截器中进行注入.即从拦截器中获取Session,然后设置进行注入. 简单的例子: 一个自定义接口,只要Action实现这个接口,就在拦截器中进行注入 package com.atguigu.surveypark.struts2; import com

Struts2自定义拦截器Interceptor以及拦截器登录实例

1.在Struts2自定义拦截器有三种方式: -->实现Interceptor接口 public class QLInterceptorAction implements Interceptor{ private static final long serialVersionUID = 1L; public void destroy() { } public void init() {} public String intercept(ActionInvocation arg0) throws

Struts2 自定义拦截器时Action无法接收到参数

问题:自定义拦截器,没有添加defaultStack导致Action无法接受到参数 解决办法: 方法一,添加defaultStack,然后在Action中引用 自定义的stack,其实defaultStack中也有细分如basicStack等 <interceptors> <interceptor name="checkUser" class="com.common.interceptor.UserInfoInterceptor"></

Spring的AOP,Struts2的拦截器(Interceptor),以及springMVC的(interceptor)

参考外链:http://www.ibm.com/developerworks/cn/java/j-lo-springaopfilter/ 1.首先,spring的AOP作用范围很广,可以使用Aspectj的execution表达式自定以切面的位置. 比如下面的配置service方法执行日志: 1 <!-- 系统日志 --> 2 <bean id="logUtils" class="com.tabchanj.crm.utils.SystemLogUtils&q

【struts2】拦截器的工作模拟实现

Main.java /** * 书本:[struts2] * 功能:模拟拦截器的工作,实际就是递归的思想 * 文件:Main.java * 时间:2014年11月9日20:04:55 * 作者:cutter_point */ public class Main { public static void main(String [] args) { new ActionInvocation().invoke(); } } ActionInvocation.java /** * 书本:[struts