struts2之配置拦截器

struts2之配置拦截器

什么是拦截器

  • java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
  • 拦截器是可插拔式的,一旦出现了问题,可以不用改变软件的很多代码就可以实现修复,给维护工作带来方便,其实过滤器也是这样的。
  • Struts2其实就实现了很多的拦截器,可以在struts-default.xml中看到定义很多的拦截器,其中向类型转换,文件上传都是通过拦截器实现的。
  • Struts2拦截器实现原理与Servlet过滤器实现原理类似,它以链式执行,对真正要执行的方法(execute())进行拦截。首先执行Action配置的拦截器,在Action和Result执行之后,拦截器会再次执行(与先前调用的顺序相反),在此链式执行的过程中,每一个拦截器都可以直接返回,从而终止余下的拦截器、Action及Result的执行。

拦截器的作用

  • 拦截器适合封一些通用处理,便于重复利用,比如日志的记录,访问权限的检查,事务处理等,拦截器通过配置方式调用,因此使用方法比较灵活,便于维护和扩展

拦截器的配置元素

  • <interceptors>用来定义拦截器,所有的拦截器和拦截器栈都是在此元素中定义的,可以包含子元素<interceptor>,<interceptor-stack>
  • <Interceptor>用来定义拦截器,需要指定两个属性,name属性指定了拦截器的名字,class指定了拦截器的实现的类。这个是在<interceptors>下定义的
  • <interceptor-stack>用来定义拦截器栈,其中的name属性指定了拦截器栈的名称。另外在此元素下可以指定<interceptor-ref>引入其他的拦截器或者拦截器栈
  • <interceptor-ref>用来引用其他的拦截器或者拦截器栈,name属性指定了拦截器或者拦截栈的名称
  • <param>用来为拦截器指定参数,可以作为<interceptor>或者<interceptor-ref>的子元素。并且可以定义多个。其中的name属性指定了参数的名称
  • <default-interceptor-ref>将某一个拦截器定义为默认拦截器

内建的拦截器

  • struts2中提供了许多内建的拦截器,在struts-core.jar中,我们只需要在struts.xml中引用这个内建的拦截器即可
  • 比如我们在实现文件上传的时候,使用的就是内建的拦截器
  • 内建的拦截器使用的很少,通常我们都是使用自定义的拦截器,比如验证访问权限的拦截器

自定义拦截器

  • 实现自定义的拦截器有两种方法,一种是实现接口,一种是继承

需求

  • 我们需要将表单传递过来的数据转换成大写的,再传递给action

实现接口(com.opensymphony.xwork2.interceptor.Interceptor)

接口中的方法

  • void init()初始化拦截器执行的方法
  • String intercept(ActionInvocation invocation) throws Exception实现拦截器逻辑的主要方法。
    • ActionInvocation包含了Action的引用,因此使用这个对象可以对Action进行相应的操作,比如可以获取和设置Action类的成员变量
    • ActionInvocation包含了Action的引用,可以调用其中的invoke()方法继续调用下一个拦截器,如果后面没有拦截器了,那么就会执行Action中对应的映射方法,如果有,那么就会继续执行下一个拦截器,直到执行完全部的拦截器才会执行对应的映射方法
    • invoke()方法将拦截器的作用分成了两个部分,在调用invoke()之前的实在Action方法执行之前的逻辑,在之后的代码是在Action执行result,跳转到指定视图之后执行的逻辑
    • 这个方法返回的是一个字符串,对应的也是结果视图,如果在其中没有调用invoke()方法,那么返回的字符串就作为Action跳转的视图,因此在<result>一定要定义这个对应的视图。如果调用了invoke()方法,那么返回的字符串就会失效,就会以Action中方法返回的字符串为主
  • void destroy() 销毁拦截器开启的资源

实现

  • 拦截器类
    • 这里并没有在init和destroy方法中写什么逻辑,可以根据实际情况来定义其中的逻辑
import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
​
public class TestInterceptor implements Interceptor{
​
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
    @Override
    public void init() {
        // TODO Auto-generated method stub
​
    }
​
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object object=invocation.getAction();  //获取当前调用拦截器的Action类的对象
        //如果不为null,就可以获取其中的属性,否则空指针
        if (object!=null) {
            SimpleAction simpleAction=(SimpleAction)object;
            //将User属性全部转换成大写字母
            simpleAction.getUser().setName(simpleAction.getUser().getName().toUpperCase());
            simpleAction.getUser().setPassword(simpleAction.getUser().getPassword().toUpperCase());
            String result=invocation.invoke();   //调用下一个拦截器
            System.out.println("成功跳转视图后执行的逻辑");
            return result;
        }
            return null;
    }
}
​

继承AbstractInterceptor(推荐)

  • 继承AbstractInterceptor抽象类,里面只有一个抽象方法String intercept(ActionInvocation invocation),只需要实现这个方法即可,如果你需要初始化和销毁,那么也可以覆盖其中的init()和destroy()方法
  • 继承抽象类的方式比实现接口对一个类的更加简洁,对这个类的污染更加小
  • 其中的方法逻辑还是和上面的一样
  • 还是完成上面的需求,把传递的请求参数转换成大写字母
import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
//继承类AbstractInterceptor
public class AbstractInterceptorTest extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object object = invocation.getAction(); // 获取当前调用拦截器的Action类的对象
        // 如果不为null,就可以获取其中的属性,否则空指针
        if (object != null) {
            SimpleAction simpleAction = (SimpleAction) object;
            // 将User属性全部转换成大写字母
            simpleAction.getUser().setName(
                    simpleAction.getUser().getName().toUpperCase());
            simpleAction.getUser().setPassword(
                    simpleAction.getUser().getPassword().toUpperCase());
            String result = invocation.invoke(); // 调用下一个拦截器
            System.out.println("成功跳转视图后执行的逻辑");
            return result;
        }
        return null;
    }
}
​

配置拦截器

  • 因为struts2的很多功能都要依赖内建的拦截器,比如表单传值。这一系列的拦截器都定义在一个拦截器栈中,如果在一个<action>中引用了拦截器,那么这拦截器就会被覆盖,因此一定要在自定义的拦截器之前定义默认的拦截器栈<interceptor-ref name="defaultStack"></interceptor-ref>
  • 配置拦截器只需要在<package>下定义拦截器即可,如果哪个action想要引用拦截器,使用<interceptor-ref >引用已经定义好的拦截器即可
  • 一个action中可以引用多个拦截器,在上面配置的拦截器先执行,因此默认的拦截器栈一定要在最上面
  • 在struts.xml中配置上面我们自定义的拦截器
<package name="test" extends="struts-default" namespace="/">
        <!--  定义拦截器 -->
        <interceptors>
            <!-- 实现接口的拦截器 -->
            <interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
​
            <!-- 继承类的 -->
            <interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
        </interceptors>
​
        <action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
            <result name="success">/jsp/success.jsp</result>
            <result name="input">/jsp/input.jsp</result>
​
            <!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
            <interceptor-ref name="defaultStack"></interceptor-ref>
​
            <!-- 引用自定义的拦截器,在上面要定义    -->
            <interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
​
            <interceptor-ref name="testInterceptor"></interceptor-ref>
        </action>
    </package>

配置拦截器栈

  • 如果一个action中的需要用到的拦截器很多,或者同时引用几个相同的拦截器的action很多,那么我们此时在action一个一个的引用拦截器效率太低,此时我们就需要将这些拦截器定义在一个拦截器栈中,直接在action中引用了拦截器栈即可。
  • 直接使用<interceptors>标签中使用<interceptor-stack name>定义即可
  • 拦截器栈中的拦截器一定要在上面定义过的,否则将会引用出错
  • 拦截器栈中的拦截器引用是有顺序的,在上面的拦截器最先执行
  • 我们把上面自定义的两个拦截器放在拦截器栈中,并在action中引用拦截器栈,注意此时的默认的default-stack还是要放在最上面
<package name="test" extends="struts-default" namespace="/">
        <!--  定义拦截器 -->
        <interceptors>
            <!-- 实现接口的拦截器 -->
            <interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
​
            <!-- 继承类的 -->
            <interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
​
            <!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
            <interceptor-stack name="myStack">
                <!-- 引用自定义的拦截器,在上面要定义 -->
                <interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
                <interceptor-ref name="testInterceptor"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
​
        <action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
            <result name="success">/jsp/success.jsp</result>
            <result name="input">/jsp/input.jsp</result>
​
            <!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
            <interceptor-ref name="defaultStack"></interceptor-ref>
​
            <interceptor-ref name="myStack"></interceptor-ref>
        </action>
</package>
​

拓展

  • 拦截器中还可以包含其他的拦截器栈,那么此时我们就可以将struts2中内建的拦截器放在自己的拦截器栈顶,那么就不用在每个action中引用了,直接引用这个拦截器栈即可
<package name="test" extends="struts-default" namespace="/">
        <!--  定义拦截器 -->
        <interceptors>
            <!-- 实现接口的拦截器 -->
            <interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
​
            <!-- 继承类的 -->
            <interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
​
            <!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
            <interceptor-stack name="myStack">
                <!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
                <interceptor-ref name="defaultStack"></interceptor-ref>
​
                <!-- 引用自定义的拦截器,在上面要定义 -->
                <interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
                <interceptor-ref name="testInterceptor"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
​
        <action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
            <result name="success">/jsp/success.jsp</result>
            <result name="input">/jsp/input.jsp</result>
​
            <interceptor-ref name="myStack"></interceptor-ref>
        </action>
</package>

自定义默认的拦截器栈

  • 在一个包中定义一个默认的拦截器栈后(使用<default-interceptor-ref>定义),那么当<action>下没有显式的配置拦截器的时候,那么此时就会默认使用自定义的默认的拦截器或者默认的拦截器栈。
  • 一个包中只能定义一个默认的拦截器,如果想要定义多个拦截器可以使用拦截器栈,定义一个默认的拦截器栈即可解决。
  • 在定义了默认的拦截器之后一定要在每一个action都定义系统默认的拦截器栈defaultStack,前面已经说过如果action定义了拦截器(这里虽然不是显式的定义,但是实际上是定义了),那么就会失去defaultStack的作用,其实我们需要很多defaultStack的功能,因此还是要定义的。
  • 比如登录检查的拦截器,这个是每一个action都需要用到的,那么我们可以设置一个默认的拦截器栈,栈顶引用的是struts2内建的默认的拦截器栈
  • 使用<default-interceptor-ref name=""></default-interceptor-ref> 即可定义
<struts>
    <package name="test" extends="struts-default" namespace="/">
        <!--  定义拦截器 -->
        <interceptors>
            <!-- 实现接口的拦截器 -->
            <interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
​
            <!-- 继承类的 -->
            <interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
​
            <!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
            <interceptor-stack name="myStack">
                <!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 引用自定义的拦截器,在上面要定义 -->
                <interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
                <interceptor-ref name="testInterceptor"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
​
        <!-- 定义默认的拦截器栈,其中引用了上面定义的拦截器栈 -->
        <default-interceptor-ref name="myStack"></default-interceptor-ref>
​
        <action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
            <result name="success">/jsp/success.jsp</result>
            <result name="input">/jsp/input.jsp</result>
        </action>
    </package>
</struts>
​

配置拦截方法的拦截器

  • 一般我们的Action类中有很多的方法,但是我们在使用动态调用的时候会调用其中不同的方法,如果不想Action类中的某个方法不被拦截,此时就需要使用拦截方法的拦截器
  • 其中可以设置拦截的方法,也可以设置不拦截的方法

自定义拦截器类

  • 继承MethodFilterInterceptor
  • 其中的方法doIntercept是在执行其中指定方法之前执行,和前面的逻辑一样,也有invoke方法
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
​
public class SimpleActionInteceptor extends MethodFilterInterceptor{
    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        System.out.println("拦截方法的拦截器起了作用");
        String result=invocation.invoke();
        System.out.println("执行之后");
        return result;
    }
}
​

struts中配置

  • <param name="excludeMethods">login</param> 用来定义不拦截的方法
  • <param name="includeMethods">regist</param> 用来定义拦截的方法,如果有多个使用逗号隔开
  • 这里使用的是动态调用的method的,但是我们也可以使用 action!方法名
  • 假设我们的项目名称为web1,并且把method=“”去掉,那么我们开启action!方法名进行调用,具体方法前面有介绍,开启之后,我们在地址栏输入 http://localhost:8080/web1/simple.regist,将会成功被拦截器拦截器,但是我们输入http://localhost:8080/web1/simple.login,拦截器不起作用
<package name="test" extends="struts-default" namespace="/">
        <!--  定义拦截器 -->
        <interceptors>
            <!-- 配置拦截方法的拦截器 -->
            <interceptor name="simpleMethod" class="com.jsnu.struts2.Interceptor.SimpleActionInteceptor"></interceptor>
        </interceptors>
​
        <action name="simple" class="com.jsnu.struts2.controller.SimpleAction" method="regist">
            <result name="success">/jsp/success.jsp</result>
            <result name="input">/jsp/input.jsp</result>
            <!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="simpleMethod">
                <!-- 定义不拦截login方法 -->
                <param name="excludeMethods">login</param>
                <!-- 定义需要拦截器的方法 -->
                <param name="includeMethods">regist</param>
            </interceptor-ref>
        </action>
    </package>

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码神联盟

珍藏 | Java 岗位 100道 面试题及答案详解

8995
来自专栏性能与架构

Zookeeper实例 - 分布式锁

需求场景 在分布式系统中,通常会有多个子系统需要操作同一资源,例如修改数据存储中的某一数据 这些子系统各自独立,操作共享资源时没有逻辑顺序,有可能会出现同时...

3665
来自专栏黑泽君的专栏

day25_day27_Struts2_学习回顾

        表现层、MVC模式。 2、Struts1和Struts2的一个显著区别是什么?     答:

1025
来自专栏linux、Python学习

十分钟带你了解 Python3 多线程核心知识

每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

2070
来自专栏塔奇克马敲代码

在使用Qt5.8完成程序动态语言切换时遇到的问题

2404
来自专栏我的博客

PHP5.3~PHP5.5新特性汇总

一.PHP 5.3中的新特性 1. 支持命名空间 (Namespace) 2. 支持延迟静态绑定(Late Static Binding) 3. 支持got...

3818
来自专栏noteless

javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码

然后使用      65------>$ 另外一种解码方式解读,显然A就变成了$,这不就是乱码了么

1773
来自专栏13blog.site

org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression

前言 本文中提到的解决方案,源码地址在:springboot-thymeleaf,希望可以帮你解决问题。 本文中涉及的两个异常为我开发时遇到的,可能和你目前所要...

4123
来自专栏Java学习之路

Hibernate学习---用Session实现CURD

我们使用Hibernate的目的是什么?对数据库进行操作,所有接下来我们就用Hibernate来进行CURD。 前边我们已经分析过了Configuration,...

4026
来自专栏架构之路

Struts2 中的值栈的理解

通过对struts2的一段时间的接触,将自己对OGNL的核心值栈说说,值栈:简单的说,就是存放action的堆栈,当我们提交一个请求道服务器端 action时,...

2673

扫码关注云+社区

领取腾讯云代金券