拦截器概述

Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP(Aspect Oriented Programming,面向切面编程)的一种实现

拦截器栈(InterceptorStack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口声明了3个方法

void init();

void destroy();

Stringintercept(ActionInvocation invocation) throws Exception;

其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。

intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑

不过,struts中又提供了几个抽象类来简化这一步骤

public abstractclass AbstractInterceptor implementsInterceptor;

public abstractclass MethodFilterInterceptorextends AbstractInterceptor;

都是模板方法实现的。

其中AbstractInterceptor提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;

而MethodFilterInterceptor则提供了includeMethodsexcludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。

实例

直接实现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(ActionInvocationinvocation) throws Exception {
             System.out.println("Action执行前插入 代码");
             //执行目标方法 (调用下一个拦截器, 或执行Action)
             final String res =invocation.invoke();
             System.out.println("Action执行后插入 代码");
             return res;
      }
}

配置

<package name="default" extends="struts-default">
      <interceptors>
             <interceptor name="MyInterceptor" class="interceptor.MyInterceptor"></interceptor>
             <interceptor-stack name="myInterceptorStack">
                    <interceptor-ref name="MyInterceptor"/>
                    <interceptor-ref name="defaultStack"/>
             </interceptor-stack>
</interceptors>

      <action name="loginAction" class="loginAction">
             <result name="fail">/index.jsp</result>
             <result name="success">/success.jsp</result>
             <interceptor-ref name="myInterceptorStack"></interceptor-ref>
      </action>
</package>

特别注意,在使用拦截器的时候,最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,否则出错

继承AbstractInterceptor抽象类

我们尝试编写一个Session过滤用的拦截器,该拦截器查看用户Session中是否存在特定的属性(LOGIN属性)如果不存在,中止后续操作定位到LOGIN,否则执行原定操作,代码为:

public class CheckLoginInterceptor extends AbstractInterceptor {
    public static final String LOGIN_KEY = "LOGIN";
    public static final String LOGIN_PAGE = "global.login";

    public String intercept(ActionInvocationactionInvocation) throws Exception {

        System.out.println("begin checklogin interceptor!");
        // 对LoginAction不做该项拦截
        Object action = actionInvocation.getAction();
        if (action instanceof LoginAction) {
            System.out.println("exit checklogin, because this is login action.");
            return actionInvocation.invoke();
        }

        // 确认Session中是否存在LOGIN
        Map session = actionInvocation.getInvocationContext().getSession();
        String login = (String)session.get(LOGIN_KEY);
        if (login != null &&login.length() > 0) {
            // 存在的情况下进行后续操作。
            System.out.println("alreadylogin!");
            return actionInvocation.invoke();
        } else {
            // 否则终止后续操作,返回LOGIN
            System.out.println("no login,forward login page!");
            return LOGIN_PAGE;
        }
    }
}

注册拦截器

<interceptors>
      <interceptor name="login"  class="com.clf.CheckLoginInterceptor"/>
            <interceptor-stack name="teamwareStack">
                <interceptor-ref name="login"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
</interceptors>

将上述拦截器设定为默认拦截器:

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

这样在后续同一个package内部的所有Action执行之前都会被login拦截。

继承MethodFilterInterceptor抽象类

MethodFilterInterceptor类重写了AbstractInterceptor类的intercept(ActionInvocationinvocation)方法,但提供了一个doIntercept(ActionInvocation invocation)抽象方法。从这种设计方式可以看出,MethodFilterInterceptor类的intercept已经实现了对Action的拦截行为(只是实现了方法过滤的逻辑),但真正的拦截逻辑还需要开发者提供,也就是通过回调doIntercept方法实现。可见,如果用户需要实现自己的拦截逻辑,则应该重写doIntercept(ActionInvocation
invocation)方法。

下面是一个简单的方法过滤的示例应用,方法过滤的拦截器代码如下。

//拦截方法的拦截器,应该继承MethodFilterInterceptor抽象类

public class MyFilterInterceptor extends MethodFilterInterceptor{

	//简单拦截器的名字
	private String name;
	//为该简单拦截器设置名字的setter方法
	public void setName(String name){
  		this.name = name;
	}

	//重写doIntercept方法,实现对Action的拦截逻辑
	public String doIntercept(ActionInvocation invocation)  throws Exception{

  //取得被拦截的Action实例
  LoginAction action = (LoginAction)invocation.getAction();

  //打印执行开始的时间
  System.out.println(name + " 拦截器的动作---------"
    + "开始执行登录Action的时间为:" + new Date());

  //取得开始执行Action的时间
  long start = System.currentTimeMillis();

  //执行该拦截器的后一个拦截器,或者直接指定Action的execute方法
  String result = invocation.invoke();

  //打印执行结束的时间
  System.out.println(name + " 拦截器的动作---------"
    + "执行完登录Action的时间为:" + new Date());
  long end = System.currentTimeMillis();

  //打印执行该Action所花费的时间
  System.out.println(name + " 拦截器的动作---------"
    + "执行完该Action的事件为" + (end - start) + "毫秒");

  return result;
	}
}

从上面的代码中可以看出,上面拦截器的拦截逻辑与前面简单拦截器的拦截逻辑相似,只是之前是需要重写intercept方法,现在是重写doIntercept方法。

实际上,实现方法过滤的拦截器与实现普通拦截器并没有太大的区别,只需要注意两个地方:实现方法过滤的拦截器需要继承MethodFilterInterceptor抽象类,并且重写doIntercept方法定义对Action的拦截逻辑。

在MethodFilterInterceptor方法中,额外增加了如下两个方法:

public void setExcludeMethods(String excludeMethods):排除需要过滤的方法——设置方法“黑名单”,所有在excludeMethods字符串中列出的方法都不会被拦截。

public void setIncludeMethods(String includeMethods):设置需要过滤的方法——设置方法“白名单”,所有在includeMethods字符串中列出的方法都会被拦截。

注意:如果一个方法同时在excludeMethods和includeMethods中列出,则该方法会被拦截。

因为MethodFilterInterceptor类包含了如上的两个方法,则该拦截器的子类也会获得这两个方法。可以在配置文件中指定需要被拦截,或者不需要被拦截的方法。

方法过滤示例应用的配置片段如下:

<!-- 配置本系统所使用的包 -->
<package name="clf" extends="struts-default">

<!-- 应用所需使用的拦截器都在该元素下配置 -->
<interceptors>
  <!-- 配置mysimple拦截器 -->
  <interceptor name="mysimple"   class="com.clf.MyFilterInterceptor">
    <!-- 为拦截器指定参数值 -->
    <param name="name">拦截方法的拦截器</param>
  </interceptor>
</interceptors>

<action name="loginPro" class="com.clf.LoginAction">
  <result name="error">/WEB-INF/content/error.jsp</result>
  <result name="success">/WEB-INF/content/welcome.jsp</result>

  <!-- 配置系统的默认拦截器 -->
  <interceptor-ref name="defaultStack"/>
  <!-- 应用自定义的mysimple拦截器 -->
  <interceptor-ref name="mysimple">
    <!-- 重新指定name属性的属性值 -->
    <param name="name">改名后的拦截方法过滤拦截器</param>
    <!-- 指定execute方法不需要被拦截 -->
    <param name="excludeMethods">execute</param>
  </interceptor-ref>
</action>
<action name="*">
  <result>/WEB-INF/content/{1}.jsp</result>
</action>
</package>

上面配置文件的代码通过excludeMethods属性指定了execute方法无须被拦截,如果浏览者在浏览器中再次向login的Action发送请求,在Tomcat控制台将看不到任何输出,表明该拦截器没有拦截Action的execute方法。

如果需要同时指定多个方法不被该拦截器拦截,则多个方法之间以英文逗号(,)隔开。看如下的配置片段:

Struts 2中提供了这种方法过滤的拦截器有如下几个:

TokenInterceptor

TokenSessionStoreInterceptor

DefaultWorkflowInterceptor

ValidationInterceptor

Struts2自带拦截器

Alias Interceptor                          alias

在不同请求之间将请求参数在不同名字件转换,请求内容不变

Chaining Interceptor                      chain

让前一个Action的属性可以被后一个Action访问,现在和chain类型的result(<resulttype="chain">)结合使用。

Checkbox Interceptor                    checkbox

添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的checkbox。

Cookies Interceptor                       cookies

使用配置的name,value来是指cookies

Conversion Error Interceptor        conversionError

将错误从ActionContext中添加到Action的属性字段中。

Create Session Interceptor            createSession

自动的创建HttpSession,用来为需要使用到HttpSession的拦截器服务。

Debugging Interceptor                  debugging

提供不同的调试用的页面来展现内部的数据状况。

Execute and WaitInterceptor        execAndWait

在后台执行Action,同时将用户带到一个中间的等待页面。

Exception Interceptor                    exception

将异常定位到一个画面

File Upload Interceptor                  fileUpload

提供文件上传功能

I18n Interceptor                             i18n

记录用户选择的locale

Logger Interceptor                         logger

输出Action的名字

Message Store Interceptor            store

存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。

Model Driven Interceptor              model-driven

如果一个类实现了ModelDriven,将getModel得到的结果放在ValueStack中。

Scoped Model Driven                    scoped-model-driven

如果一个Action实现了ScopedModelDriven,则这个拦截器会从相应的Scope中取出model调用Action的setModel方法将其放入Action内部。

Parameters Interceptor                 params

将请求中的参数设置到Action中去。

Prepare Interceptor                       prepare

如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。

Scope Interceptor                          scope

将Action状态存入session和application的简单方法。

Servlet Config Interceptor             servletConfig

提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方式访问。

Static Parameters Interceptor              staticParams

从struts.xml文件中将<action>中的<param>中的内容设置到对应的Action中。

Roles Interceptor                           roles

确定用户是否具有JAAS指定的Role,否则不予执行。

Timer Interceptor                          timer

输出Action执行的时间

Token Interceptor                           token

通过Token来避免双击

Token Session Interceptor              tokenSession

和Token Interceptor一样,不过双击的时候把请求的数据存储在Session中

Validation Interceptor             validation

使用action-validation.xml文件中定义的内容校验提交的数据。

Workflow Interceptor             workflow

调用Action的validate方法,一旦有错误返回,重新定位到INPUT画面

Parameter Filter Interceptor  N/A

从参数列表中删除不必要的参数

Profiling Interceptor               profiling

通过参数激活profile

注册并引用Interceptor

<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="redirect-action">/secure/home</result>
   </action>
</package>

可以将多个拦截器合并在一起作为一个堆栈调用,当一个拦截器堆栈被附加到一个Action的时候,要想Action执行,必须执行拦截器堆栈中的每一个拦截器。

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

    <action name="login" class="tutuorial.Login">
         <interceptor-ref name="myStack"/>
         <result name="input">login.jsp</result>
         <result name="success"
             type="redirect-action">/secure/home</result>
    </action>
</package>

上述说明的拦截器在默认的Struts2应用中,根据惯例配置了若干个拦截器堆栈,详细情参看struts-default.xml

其中有一个拦截器堆栈比较特殊,他会应用在默认的每一个Action上。

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="profiling"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="params">
      <param name="excludeParams">dojo"..*</param>
    </interceptor-ref>
    <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-stack>
 

每一个拦截器都可以配置参数,有两种方式配置参数,一是针对每一个拦截器定义参数,二是针对一个拦截器堆栈统一定义所有的参数,例如:

<interceptor-ref name="validation">
 <param name="excludeMethods">myValidationExcudeMethod</param>
</interceptor-ref>
<interceptor-ref name="workflow">
 <param name="excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>

或者

<interceptor-ref name="defaultStack">
    <param name="validation.excludeMethods">myValidationExcludeMethod</param>
    <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>

每一个拦截器都有两个默认的参数:

excludeMethods - 过滤掉不使用拦截器的方法和

includeMethods – 使用拦截器的方法。

拦截器执行的顺序按照定义的顺序执行

Struts 2 之拦截器的更多相关文章

  1. Struts 2的拦截器(Interceptor)总结

     什么是Struts 2拦截器? 从软件构架上来说,拦截器是实现了面向方面编程的组件.它将影响了多个业务对象的公共行为封装到一个个可重用的模块,减少了系统的重复代码,实现功能的高度内聚,确保了业务对象 ...

  2. struts过滤器和拦截器的区别

    拦截器的工作原理:当接收到一个httprequest ,a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标准的过滤器链 c) FilterDisp ...

  3. struts详细解释拦截器

    1.拦截器:Struts2拦截器将一个Action要么Action的方法.之前或截取后场,和Struts2拦截器是可插拔,拦截器AOP一种实现. WebWork:拦截器是动态拦截Action调用的对象 ...

  4. struts自己定义拦截器--登录权限控制

    说明:该自己定义的拦截器实现用户登录的权限控制. login.jsp--->LoginAction--重定向-->MainAction--->main.jsp 一.1.整体的步骤: ...

  5. Struts的拦截器

    Struts的拦截器 1.什么是拦截器 Struts的拦截器和Servlet过滤器类似,在执行Action的execute方法之前,Struts会首先执行Struts.xml中引用的拦截器,在执行完所 ...

  6. Struts 2学习笔记——拦截器相关

    一.添加国际化支持 默认的struts-deault.xml文件中已经定义了国际化拦截器,内容如下 <!-定义国际化拦截器--> <interceptor name="i1 ...

  7. struts自定义拦截器

    第01步:配置web.xml,启动struts框架 <?xml version="1.0" encoding="UTF-8"?> <web-a ...

  8. struts拦截器

    struts中的拦截器相当于过滤器的作用 一在struts.xml中配置拦截器或拦截器栈 <interceptors>!--全部的拦截器 <interceptor name=&quo ...

  9. [置顶] 使用struts拦截器+注解实现网络安全要求中的日志审计功能

    J2EE项目中出于安全的角度考虑,用户行为审计日志功能必不可少,通过本demo可以实现如下功能: 1.项目中记录审计日志的方法. 2.struts拦截器的基本配置和使用方法. 3.struts拦截器中 ...

随机推荐

  1. [ZJOI 2010]base 基站选址

    Description 题库链接 给出 \(n\) 个村庄的横坐标 \(D_i\) .要求在这 \(n\) 个村庄内最多选择 \(m\) 个作为通讯基站,在村庄 \(i\) 建造通讯基站的代价为 \( ...

  2. 计蒜客NOIP模拟赛4 D2T2 跑步爱天天

    YOUSIKI 在 noip2016 的一道<天天爱跑步>的题爆零后,潜心研究树上问题,成为了一代大师,于是皮皮妖为了测验他,出了一道题,名曰<跑步爱天天>. 有一个以 1 为 ...

  3. ●BZOJ 1185 [HNOI2007]最小矩形覆盖

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1185 题解: 计算几何,凸包,旋转卡壳 结论:矩形的某一条边在凸包的一条边所在的直线上. ( ...

  4. ●BZOJ 3931 [CQOI2015]网络吞吐量

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3931 题解: 在最短路图上跑网络流,要开long long(无奈 BZOJ AC 不了,洛谷 ...

  5. 习题10-1 UVA 11040(无聊水一水)

    题意: 给你一个残缺的塔,每个数字由他下面左右两个数相加得.给你其中一部分,要求输出全部的数字. #include <iostream> #include <cstdio> # ...

  6. [BZOJ]1045 糖果传递(HAOI2008)

    放一道数学题. Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数n<=1000000,表示 ...

  7. Gradle学习之闭包

    Gradle中的闭包其实就等同于Groovy中闭包,Groovy是一种jvm语言,语法兼容于java,曾几何时,也在脚本语言中独树一帜,初学Gradle的时候,大家很容易被其语法所迷惑,由于Gradl ...

  8. c# 虚拟路径转化为物理路径

    string strPhycicsPath= Server.MapPath(path);

  9. Java并发之BlockingQueue的使用

    Java并发之BlockingQueue的使用 一.简介 前段时间看到有些朋友在网上发了一道面试题,题目的大意就是:有两个线程A,B,  A线程每200ms就生成一个[0,100]之间的随机数, B线 ...

  10. 一个页面从输入url到页面加载显示完成,中间都经历了什么

    第一种解释: 一般会经历以下几个过程: 1.首先,在浏览器地址栏中输入url 2.浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容.若没有,则跳到第三步操作. 3 ...