前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >struts2之配置拦截器

struts2之配置拦截器

原创
作者头像
爱撒谎的男孩
发布2018-05-10 18:58:46
1K1
发布2018-05-10 18:58:46
举报
文章被收录于专栏:码猿技术专栏码猿技术专栏

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方法中写什么逻辑,可以根据实际情况来定义其中的逻辑
代码语言:javascript
复制
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()方法
  • 继承抽象类的方式比实现接口对一个类的更加简洁,对这个类的污染更加小
  • 其中的方法逻辑还是和上面的一样
  • 还是完成上面的需求,把传递的请求参数转换成大写字母
代码语言:javascript
复制
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中配置上面我们自定义的拦截器
代码语言:javascript
复制
<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还是要放在最上面
代码语言:javascript
复制
<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中引用了,直接引用这个拦截器栈即可
代码语言:javascript
复制
<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> 即可定义
代码语言:javascript
复制
<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方法
代码语言:javascript
复制
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,拦截器不起作用
代码语言:javascript
复制
<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>

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • struts2之配置拦截器
    • 什么是拦截器
      • 拦截器的作用
        • 拦截器的配置元素
          • 内建的拦截器
            • 自定义拦截器
              • 需求
              • 实现接口(com.opensymphony.xwork2.interceptor.Interceptor)
              • 继承AbstractInterceptor(推荐)
            • 配置拦截器
              • 配置拦截器栈
                • 拓展
              • 自定义默认的拦截器栈
                • 配置拦截方法的拦截器
                  • 自定义拦截器类
                  • struts中配置
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档