strtus2.xml 配置文件

本文深入解析Struts2框架中的拦截器配置方法,包括拦截器的基本概念、实现方式、自定义拦截器的步骤、配置拦截器栈的技巧以及如何配置默认拦截器。文章还探讨了拦截器在Action执行前后的运作机制,以及如何利用拦截器进行日志记录、权限检查等通用处理。

struts2之配置拦截器 学习笔记

struts2之配置拦截器

什么是拦截器

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

拦截器的作用

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

内建的拦截器

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跳转的视图,因此在一定要定义这个对应的视图。如果调用了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想要引用拦截器,使用引用已经定义好的拦截器即可
一个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中引用了拦截器栈即可。
直接使用标签中使用定义即可
拦截器栈中的拦截器一定要在上面定义过的,否则将会引用出错
拦截器栈中的拦截器引用是有顺序的,在上面的拦截器最先执行
我们把上面自定义的两个拦截器放在拦截器栈中,并在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>

自定义默认的拦截器栈

在一个包中定义一个默认的拦截器栈后(使用定义),那么当下没有显式的配置拦截器的时候,那么此时就会默认使用自定义的默认的拦截器或者默认的拦截器栈。
一个包中只能定义一个默认的拦截器,如果想要定义多个拦截器可以使用拦截器栈,定义一个默认的拦截器栈即可解决。
在定义了默认的拦截器之后一定要在每一个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中配置

login 用来定义不拦截的方法 regist 用来定义拦截的方法,如果有多个使用逗号隔开 这里使用的是动态调用的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>

1:所有拦截器的超级接口Interceptor ,Action去实现这个接口;

Interceptor 它其中有三个方法(init(),destroy() ,interceptor()):

  Init()方法:在服务器起动的时候加载一次,并且只加载一次;

  Destroy()方法:当拦截器销毁时执行的方法;

  Interceptor()方法:其中里边有一个参数invocation
public String intercept(ActionInvocation invocation) throws xception {

       System.out.println("interceptor!!");

       String result=invocation.invoke();

       return result;

    }

Invocation.invoke()是如果只有一个拦截器执行完这个方法后,会返回给视图,如果有多个拦截器,它顺序的执行完所有的拦截器,才返回给视图.

2:可以在系统初始化中给拦截器指定默认的参数(也包括了定义拦截器方式)如下:

在拦截器类中把hello当做属性set/get方式注入到拦截器类中;

  <interceptors>

       <!-- 先定义拦截器 -->

       <interceptor name="myInterceptor" class="com.zzz.struts2.interceptor.MyInterceptor">

          <!-- 指定系统初始化给拦截器的参数 -->

          <param name="hello">张钊钊</param>

       </interceptor>

       <!-- 加到自己设置的拦截器栈里边去 -->

       <interceptor-stack name="myStack">

          <interceptor-ref name="myInterceptor">

          </interceptor-ref>

          <interceptor-ref name="defaultStack"></interceptor-ref>

       </interceptor-stack>

   </interceptors>

   <!-- 改变系统默认的拦截器,改成自己的默认拦截器,并且一个系统只能有一个默认的拦截器,这样这个拦截器栈会默认应用到所有的Action上去 -->

   <default-interceptor-ref name="myStack">

   </default-interceptor-ref>

   也可以在使用拦截器的时候给它设置参数:

   就是在一个action 的reslut下面配置上如下:
<action name="register"

       class="com.zzz.struts2.action.RegisterAction">

       <result name="success">/success.jsp</result>

       <!-- result 它其中还有一个信息转发类型 type=""记住,如果不转向JSP,转向图表,可以改变type=""值 -->

       <result name="input">/register.jsp</result>

      

       <interceptor-ref name="myInterceptor">

          <param name="hello">welcome</param>

       </interceptor-ref>

       <interceptor-ref name="myStack"></interceptor-ref>

   </action>

2.拦截器,拦截器栈和默认的拦截器之间的关系

1:拦截器和拦截器栈是一个级别的,也就是说一个拦截器栈中包括许多拦截器, 一个拦截器栈中还可以包括许多拦截器栈,配置如下方式:

<interceptors>

           <!-- 先定义拦截器 -->

           <interceptor name="myInterceptor" class="com.zzz.struts2.interceptor.MyInterceptor">

              <!-- 指定系统初始化给拦截器的参数 -->

              <param name="hello">张钊钊</param>

           </interceptor>

           <!-- 加到自己设置的拦截器栈里边去 -->

           <interceptor-stack name="myStack">

              <interceptor-ref name="myInterceptor">

              </interceptor-ref>

              <interceptor-ref name="defaultStack"></interceptor-ref>

           </interceptor-stack>

       </interceptors>

拦截器的使用:1.先定义;2.在引用使用;

          </interceptor-ref>

2:struts2中有一个系统默认的拦截器栈是 defaultStack,如果你手动引用自己的拦截器,系统默认的拦截器栈将不起作用;这样必需手动引入系统的拦截器栈

          </interceptor-ref>

如果想改变系统默认的拦截器栈,可以这样配置:

其中myStack是自己定义的拦截器栈名字;

如果拦截器栈中有多个拦截器,在执行action之前的顺序跟配置拦截器的顺序一致,而在action之后执行的顺序是相反的;

3:抽象的拦截器类AbstractInterceptor

1:Interceptor这个超级拦截器接口,有三方法需要实现,但是如果不想使用init();

和destroy()方法,可以去继承这个抽象拦截器类;

它的使用跟上边的没有什么区别;

4:方法过滤拦截器MethodFilterInterceptor

1:上边的拦截器都要是针对整个action的,如果针对某个方法进行拦截可以去继承这个类;

它的使用跟上边的使用方法差不多,只是需要要配置它对那个方法进行拦截,方法过滤拦截器最好不要配置到自己设置默认的拦截器栈里边,自己手动配置.

interceptor-ref name=“myInterceptor3”>

          <param name="includeMethods">execute</param>

          <param name="excludeMethods">execute</param>

       </interceptor-ref>

       <interceptor-ref name="defaultStack"></interceptor-ref>

其中includeMethods ,excludeMethods是固定写法: includeMethods 包含拦截那些方法,多个方法需要用”,”隔开; excludeMehtods是排除拦截的那些方法;

5:鉴听器PreResultListener接口

1:它的鉴听点在拦截器执行完某个action方法后,在渲染视图之前做一些事情;让某个类去实现这个接口;

然后向需要它的拦截器中注册进去如下代码:

publicclass MyInterceptor3 extends MethodFilterInterceptor {

    privatestaticfinallongserialVersionUID = 3756655410194005443L;

    @Override

    protected String doIntercept(ActionInvocation invocation) throws Exception {

       //把鉴听器注册到拦截中去;

       invocation.addPreResultListener(new MyListener());

       System.out.println("my Interceptor3");

       String result=arg0.invoke();

       System.out.println("my interceptor3 finshed!");

       return result;

    }

}

struts2采用convention-plugin实现零配置,Struts2 Convention插件的使用

https://blog.csdn.net/lexang1/article/details/52704164

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值