Struts2之-拦截器详解

什么是拦截器

拦截器是Struts2的核心组成部分,它可以动态的拦截Action调用的对象,类似与Servlet中的过滤器。Struts2的拦截器是AOP(Aspect-Object-Programming,面向切面编程)的一种实现策略,是可插拔的,需要某一个功能时就“插入”这个功能的拦截器,不需要这个功能就“拔出”拦截器。开发者只需要提供拦截器的实现类,并将其配置在Struts.xml中即可。

《Struts2之-拦截器详解》

工作流程为请求-过滤前 – 拦截前 – Action处理 – 拦截后 -过滤后-响应

滤器器、拦截器的区别:

滤器器与截器非常相似,都是面向切面编程,具体的区别如下:

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

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

3、拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。

4、拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
5、在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

6、过滤器:取你需要的东西,忽视那些不需要的东西!在程序中,你希望选择中一篇文章中的所有数字,你就可以针对性的挑选数字!

7、拦截器:针对你不要的东西进行拦截,比如说,在一个BBS里面你希望人家不要留“小乌鸦”的这个词,那你就可能采用拦截器!

8、过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts2的action前统一设置字符集,或者去除掉一些非法字符

9、拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

10、执行顺序 :过滤前 – 拦截前 – Action处理 – 拦截后 -过滤后。个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程,再向上返回到过滤器的后续操作。

拦截器的配置

1、拦截器配置

拦截器的配置在struts.xml文件中完成的,它通常以标签开头,以标签结束。定义拦截器的语法格式如下:

<interceptors>
 <interceptor name="interceptorName" class="interceptorClass">
            <param name="paramName">paramValue</param>
 </interceptor>
</interceptors>

2、拦截器栈

在实际开发中,在Action执行前同时执行多个拦截动作,如用户登陆检查等,这时可以把多个拦截器组成拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。

定义拦截器栈使用子元素,当配置多个拦截器时,需要使用元素来指定多个拦截器,配置语法如下:

<interceptors>
          <interceptor-stack name="interceptorStackName">
              <interceptor-ref name="interceptorName"/>
              ...
          </interceptor-stack>
   </interceptors>

上述语法中,interceptorStackName值表示配置的拦截器栈的名称,interceptorName值表示拦截器的名称。除此之外,在一个拦截器栈中还可以包含另一个拦截器栈

3、默认拦截器

默认拦截器可以对其指定包中的所有Action起到拦截的作用。一旦为某个包指定了默认拦截器,并且该包中的Action未显式地指定拦截器,则会使用默认拦截器。默认拦截器需要使用元素,此元素为元素的子元素。其语法格式如下:

 <default-interceptor-ref name="拦截器(栈)的名称"/>

Notice:一个包下只能定义一个默认拦截器,如果需要多个拦截器作为默认拦截器,则可以将这些拦截器定义为一个拦截器栈,再将这个拦截器栈作为默认拦截器即可。

自定义拦截器

struts2的内置拦截器可以实现大部分的拦截任务,但是一些与系统逻辑相关的通用功能(如权限的控制、用户登陆控制等),则需要通过自定义拦截器来实现。

在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接地实现com.opensymphony.xwork2. interceptor. Interceptor接口在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接地实现com.opensymphony.xwork2. interceptor. Interceptor接口.

该接口提供一下三个方法:

  • void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期只有内只被调用一次。可以在该方法中对相关的资源进行必要的初始化;
  • void destroy():该方法与init()方法相对应,在拦截器实例被销毁之前,将调用该方法来释放与拦截器相关的资源。它在拦截器的生命周期内也只被调用一次。
  • Spring intercept(ActionInvocation invocation)throws Exception:该方法是拦截器的核心方法,用来真正执行拦截工作的代码,实现具体的拦截工作。

自定义拦截器的使用分为一下三个步骤:

  • 用户自定义拦截器类,必须实现Interceptor接口或者继承AbstractInterceptor类;
  • 需要在struts.xml中,定义自定义拦截器;
  • 在struts.xml中的Action中使用拦截器。

自定义权限拦截器

简单介绍一个登陆权限下的图书管理

1、登陆页面login.jsp,提交用户名密码到LoginAction处理
2、登陆成功后跳转到书本管理页面bookM.jsp,将用户对象放在session域中
3、失败会将失败信息放在actionContext中后继续登陆,在login.jsp页面通过 ${requestScope.msg}获取失败的登陆信息

4、在bookM.jsp页面操作图书,信息提交到BookAction处理
5、BookAction有过滤器,检测session域中是否有用户对象,有的话继续,没有跳转到登陆页面
6、BookAction操作book,将信息放在ActionMessage中
7、操作完成,返回bookM.jsp页面,<s:actionmessage/>返回操作图书的信息

8、bookM.jsp有注销,动作提交给LoginAction处理
9、LoginAction删除在session中用户对象
10、删除后跳转到登陆页面login.jsp

struts.xml配置

<package name="myPackage" extends="struts-default" namespace="/">
         <interceptors>
          <interceptor name="login_interceptor" class="interceptor.PrivilegeInterceptor">
            <param name="userName">刘病已</param>
            <param name="password">123456</param>
         </interceptor>
          <interceptor-stack name="mystack">
              <interceptor-ref name="login_interceptor"/>
                <interceptor-ref name="defaultStack"></interceptor-ref>
          </interceptor-stack>
          </interceptors>
         <action name="login_*" class="action.LoginAction" method="login_{1}">
            <result>/bookM.jsp</result>
            <result name="input">login.jsp</result>
        </action>
         <!--关于book操作-->
        <action name="book_*" class="action.BookAction" method="{1}">
            <result>/bookM.jsp</result>
            <result name="login">/login.jsp</result>
            <!--在action中使用自定义拦截器-->
            <interceptor-ref name="mystack"/>
        </action>
    </package>

注意:一旦在Action中使用了自定义拦截器或拦截器栈则defaultStack就不起作用了。
使用自定义的拦截器配置在struts配置文件的action中,还要引入defaultStack,否则使用了modelDriven的formBean将不能获取到form表单中字段的值。

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

excludeMethods – 过滤掉不使用拦截器的方法和
includeMethods – 使用拦截器的方法。
拦截器需要有name属性(定义了setXxx方法)即可注入。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <title>登陆</title>
</head>
<body>
   <center>
        ${requestScope.msg}<br>
        <form action="login_in.action" method="post">
            <table>
                <tr>
                    <td><label style="text-align: right;">用户名:</label></td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td><label style="text-align: right;">密码:</label></td>
                    <td><input type="password" name="password"></td>
                </tr>
                <tr>
                    <td align="right" colspan="2">
                        <input type="submit" value="登陆">
                    </td>
                </tr>
            </table>
        </form>
   </center>
</body>
</html>

bookM.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
    <title>书本管理页面</title>
    <style type="text/css">
    .actionMessage {

    list-style: none;
    margin: 0;
    padding: 0;

}
    </style>
</head>
<body>
<s:actionmessage/>
    <a href="book_del.action">book del</a><br>
    <a href="book_add.action">book add</a><br>
    <a href="book_update.action">book update</a><br>
    <a href="book_find.action">book find</a><br>
     <a href="login_out.action">注销</a><br>
     <s:debug></s:debug>
</body>
</html>

LoginAction.java

/**
 * 
 */
package action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

import entity.Users;

/**
 * @author Administrator
 *
 */
public class LoginAction extends ActionSupport implements ModelDriven<Users>{
    private static final long serialVersionUID = 1L;
    private Users user;

    public Users getModel() {
    if(user==null){
        user = new Users();

    }
     return user;
    }


    public String login_in() throws Exception {
        //获取ActionContext
        ActionContext actionContext = ActionContext.getContext();

        if ("shadow".equals(user.getUsername()) && "123".equals(user.getPassword())) {
            actionContext.getSession().put("user", user);
            return SUCCESS;
        } else {
            actionContext.put("msg", "用户名或者密码不正确");
            return INPUT;
        }
    }
    public String login_out() throws Exception {
        //获取ActionContext
        ActionContext actionContext = ActionContext.getContext();
        actionContext.getSession().remove("user");
         return INPUT;
    }
}

BooKAction.java

/**
 * 
 */
package action;

import com.opensymphony.xwork2.ActionSupport;

/**
 * @author Administrator
 *
 */
public class BookAction extends ActionSupport{
    public String add(){
        addActionMessage("添加书本成功");
        return SUCCESS;
    }
    public String del(){
     addActionMessage("删除书本成功");
        return SUCCESS;
    }
    public String update(){
     addActionMessage("更新书本成功");
        return SUCCESS;
    }
    public String find(){
     addActionMessage("查找书本成功");
        return SUCCESS;
    }
}

PrivilegeInterceptor.java

/**
 * 
 */
package interceptor;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.TextParseUtil;

import lombok.Getter;
import lombok.Setter;

/**
 * @author Administrator
 *
 */
public class PrivilegeInterceptor extends AbstractInterceptor{
    @Getter
    @Setter
    private String userName;
    @Getter
    @Setter
    private String password;
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
    //得到ActionContext
        ActionContext actionContext = invocation.getInvocationContext();

            System.out.println("获取到拦截器定义参数"+userName);
            System.out.println("获取到拦截器定义参数"+password);
        //获取user对象
        Object user = actionContext.getSession().get("user");
        if(user != null){
            return invocation.invoke();
        }else {
            actionContext.put("msg","您还未登录,请先登陆");
            return Action.LOGIN;       //用户如果不存在,返回login直
        }
    }

}

使用拦截器注解

Struts2在com.opensymphony.xwork2.interceptor.annotations包中定义了3个拦截器注解类型,让你可以不用编写拦截器类,直接通过注解的方式指定action执行之前和之后需要调用的方法。

Struts2提供的3个拦截器注解类型都只能应用到方法级别。如下:

  • Before
    标注一个action方法,该方法将在action的主要方法(如execute方法)调用之前调用。如果标注的方法有返回值,并且不为空,那么它的返回值将作为Action的结果代码。

  • After
    标注一个action方法,该方法将在action的主要方法以及result执行之后调用,如果标注的方法有返回值,那么这个返回值将被忽略。

  • BeforeResult
    标注一个action方法,该方法将在action的主要方法调用之后,在result执行之前调用,如果标注的方法有返回值,那么这个返回值将被忽略。

Before After 和BeforeResult注解的同名参数

参数 类型 是否必要 默认值 描述
priority int 10 指定方法执行的优先级别

同一个注解可以用来标注多个方法,方法执行的先后顺序可以通过priority参数来指定,优先级越高,方法越先执行。在相同的优先级的情况下,方法执行的先后顺序无法保证。不过有继承关系的action类,在基类上标注的方法将先于在派生类上标注的方法执行。

要使用拦截器注解,需要配置

<interceptor name="annotationInterceptor" class="com.opensymphony.xwork2.interceptor.annotations. AnnotationWorkflowInterceptor"/>  

使用注解拦截器案例

<package name="myPackage" extends="struts-default" namespace="/">
         <interceptors>
         <interceptor name="annotationInterceptor" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"/>   
          <interceptor name="login_interceptor" class="interceptor.PrivilegeInterceptor">
            <param name="userName">刘病已</param>
            <param name="password">123456</param>
         </interceptor>
          <interceptor-stack name="mystack">
              <interceptor-ref name="login_interceptor"/>
               <interceptor-ref name="annotationInterceptor"/>
                <interceptor-ref name="defaultStack"></interceptor-ref>
          </interceptor-stack>
          </interceptors>

BookAction.java

/**
 * 
 */
package action;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.annotations.After;
import com.opensymphony.xwork2.interceptor.annotations.Before;
import com.opensymphony.xwork2.interceptor.annotations.BeforeResult;

/**
 * @author Administrator
 *
 */
public class BookAction extends ActionSupport{
    /**
     * 
     */
    private static final long serialVersionUID = -8082685884945619946L;
    public String add(){
        addActionMessage("添加书本成功");
        return SUCCESS;
    }
    public String del(){
     addActionMessage("删除书本成功");
        return SUCCESS;
    }
    public String update(){
     addActionMessage("更新书本成功");
        return SUCCESS;
    }
    public String find(){
     addActionMessage("查找书本成功");
        return SUCCESS;
    }
    @Before

    public void before(){
       System.out.println("before");
    }
    @After(priority=1)

    public void after(){
       System.out.println("after1");
    }
    @After(priority=2)

    public void after2(){
       System.out.println("after2");
    }
    @BeforeResult

    public void beforeResult(){
       System.out.println("beforeResult");
    }
}

结果为:

before
beforeResult
after2
after1

系统自带的拦截器

<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
  • alias:对于HTTP请求包含的参数设置别名。
  • autowiring:将某些JavaBean实例自动绑定到其他Bean对应的属性中。有点类似Spring的自动绑定,在Spring部分会详细说明。
  • Chain:在Web项目开发中,以前使用Struts开发时候经常碰到两个Action互相传递参数或属性的情况。该拦 截器就是让前一Action的参数可以在现有Action中使用。
  • conversionError:从ActionContext中将转化类型时候发生的错误添加到Action的值域错误中,在校验时候 经常被使用到来显示类型转化错误的信息。
  • cookie:从Struts2.0.7版本开始,可以把cookie注入Action中可设置的名字或值中。
  • createSession:自动创建一个HTTP的Session,尤其是对需要HTTP的Session的拦截器特别有用。比如下面 介绍的TokenInterceptor。
  • debugging:用来对在视图间传递的数据进行调试。
  • ExecAndWait:不显式执行Action,在视图上显示给用户的是一个正在等待的页面,但是Action其实是在 “背后”正在执行着。该拦截器尤其在对进度条进行开发的时候特别有用。
  • exception:将异常和Action返回的result相映射。
  • fileUpload:支持文件上传功能的拦截器。
  • i18n:支持国际化的拦截器。
  • logger:拥有日志功能的拦截器。
  • modelDriven:Action执行该拦截器时候,可以将getModel方法得到的result值放入值栈中。
  • scopedModelDriven:执行该拦截器时候,它可以从一个scope范围检索和存储model值,通过调用
    setModel:方法去设置model值。
  • params:将HTTP请求中包含的参数值设置到Action中。
  • prepare:假如Action继承了Preparable接口,则会调用prepare方法。
  • staticParams:对于在struts.xml文件中Action中设置的参数设置到对应的Action中。
  • scope:在session或者application范围中设置Action的状态。
  • servletConfig:该拦截器提供访问包含HttpServletResquest和HttpServletResponse对象的Map的方法。
  • timer:输出Action的执行时间。
  • token:避免重复提交的校验拦截器。
  • tokenSession:和token拦截器类似,但它还能存储提交的数据到session里。
  • validation:运行在action-validation.xml(校验章节将介绍)文件中定义的校验规则。
  • workflow:在Action中调用validate校验方法。如果Action有错误则返回到input视图。
  • store:执行校验功能时候,该拦截器提供存储和检索Action的所有错误和正确信息的功能。
  • checkbox:视图中如果有checkbox存在的情况,该拦截器自动将unchecked的checkbox当作一个参数(通常值为“false”)记录下来。这样可以用一个隐藏的表单值来记录所有未提交的checkbox,而且缺省
  • unchecked:的checkbox值是布尔类型的,如果视图中checkbox的值设置的不是布尔类型,它就会被覆盖成布 尔类型的值。
  • profiling:通过参数来激活或不激活分析检测功能,前提是Web项目是在开发模式下。(涉及到调试和性能 检验时使用)
  • roles:进行权限配置的拦截器,如果登录用户拥有相应权限才去执行某一特定Action

defaultStack

<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="debugging"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params">
        <param name="excludeParams">dojo\..*,^struts\..*</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>

参考

https://www.cnblogs.com/Mairr/p/7906086.html
https://blog.csdn.net/yy008871/article/details/7671395
https://blog.csdn.net/hao2244/article/details/50426693
https://www.cnblogs.com/zxl/archive/2008/11/21/1338096.html

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注