欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Struts2的拦截器

程序员文章站 2022-07-09 21:11:09
...

拦截器的认识

拦截器主要完成的工作: 对于任何MVC框架来说, 它们都会完成一-些通用的控制逻辑。

早期的Struts1框架把这些动作都写死在系统的核心控制器里。

  • 灵活性非常差:这种框架强制所有项目都必须使用该框架提供的全部功能,不管用户是否需要, 核心控制器总是会完成这些操作。
  • 可扩展性很差:如果用户需要让核心控制器完成更多自定义的处理,这就比较困难了。在Struts1时代我们都是通过扩展Struts1的核心控制器来实现的。

    Struts 2改变了这种做法,它把大部分核心控制器需要完成的工作按功能分开定义,每个拦截器完成一个功能。而这些拦截器可以*选择,灵活组合(甚至不用Struts 2的任何拦截器),开发者需要使用哪些拦截器,只需要在struts.xml文件中指定使用该拦截器即可。

Struts 内建拦截器

如果我们定义的package继承了Struts 2的默认struts-default包。就可以使用struts内建的拦截器。

Struts2的拦截器

Struts2的拦截器

Struts2的拦截器

拦截器与action关系

Struts2的拦截器

首先,通过StrutsPrepareAndExecutorFilter初始化一个ActionProxy实例,并调用它的execute方法,其次,拦截器方法会先拦截、并处理用户请求,然后,在调用Action的execute方法处理用户请求,最后,根据执行的结果,返回对应的结果视图。

拦截器的配置

拦截器的配置一般是在action的配置中

  <interceptor name=""></interceptor>//定义一个拦截器
   <interceptor-ref name=""></interceptor-ref>//引用(使用)一个拦截器

   <interceptor-stack>//拦截器栈的定义就是对拦截器的引用
   <interceptor-ref name=""></interceptor-ref>
   <interceptor-ref name=""></interceptor-ref>
   <interceptor-ref name=""></interceptor-ref>
   </interceptor-stack>

拦截器参数

  1. 定义拦截器时指定参数值:这种参数值将作为拦截器参数的默认参数值。
  2. 使用拦截器时指定参数值:在配置Action时为拦截器参数指定值。这种方式用于覆盖拦截器的默认参数值。

配置默认拦截器的注意点

当配置一个包时,可以为其指定默认拦截器(默认拦截器是正针对于package标签)。一旦为某个包指定了默认的拦截器,如果该包中的Action没有显式指定拦截器, 则默认的拦截器将会起作用。但值得注意的是, 如果一旦我们为该包中的Action显式应用了某个拦截器,则默认的拦截器不会起作用;如果该Action需要使用该默认拦截器,则必须手动配置该拦截器的引用。

实现拦截器类

虽然struts的拦截器默认提供了很多内建拦截器,可以满足绝大部分的需求的通用功能,但是还有些系统逻辑相关的通用功能,可以通过自定义拦截器去实现。

自定义的拦截器要继承AbstractInterceptor 抽象类。

public class MyFirstInterceptor extends AbstractInterceptor {
//如果你要给拦截器设置参数,你只要在这提供对应的setXxx,参数真正是在struts.xml下的拦截器配置下的param参数,那里的name就对应你在这定义的变量。
    /**
     * 拦截器实例实例化之前,需要进行的初始化工作,该方法只执行一次
     */
    @Override
    public void init() {
        // TODO Auto-generated method stub
        super.init();
    }
    /**
     * 该方法是拦截器真正工作,ActionInvocation保存了action引用,有了该引用就可以做很多事情
     * 该方法返回是action execute执行的结果视图字符串,并根据对应的视图名寻找对应的视图
     */
    @Override
    public String intercept(ActionInvocation arg0) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("action 开始执行");
        //DownAction down = (DownAction) arg0.getAction();这里可以获取拦截器的action实例
        long start = System.currentTimeMillis();
        String result = arg0.invoke();//这里相当于执行action的execute方法。
        long end = System.currentTimeMillis();
        System.out.println("action 执行时间"+(end-start));
        return result;
    }
    /**
     * 拦截器实例销毁之前,执行的操作
     */
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        super.destroy();
    }

}

配置自定义拦截器

下面的标签在写在package下,因为它是拦截器的定义。

    <interceptors>//可以看出struts的内建标签是不需要进行显示定义,直接引用,而自定义的需要显示定义。
    <interceptor name="MyFirstInterceptor" class="com.example.test.interceptor.MyFirstInterceptor"></interceptor>
    </interceptors>

下面的标签是要写在action下,使用拦截器是针对于某一个action的。

 <interceptor-ref name="MyFirstInterceptor"></interceptor-ref>
 <interceptor-ref name="defaultStack"/>/**/这里一定要注意,就是你如果引用某个拦截器,或者是自定义的,默认的拦截器,就不起作用,所以,要你显式申明一下,同时要注意,就是就是你自己引用的拦截器,一定要在你显式引用的默认拦截器之前,否则,会出现问题。**

拦截方法的拦截器

在默认情况下,如果我们为某个Action定义了拦截器,则这个拦截器会拦截该Action内的所有方法。但在某些情况下,我们不想拦截所有的方法,只需要拦截指定方法,此时就需要使用Struts 2拦截器的方法过滤特性。

定义方法拦截器需要继承于MethodFilterInterceptor。

public class MethodInterceptor extends MethodFilterInterceptor{

    @Override
    protected String doIntercept(ActionInvocation arg0) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("action 方法的拦截器来了");
        String result = arg0.invoke();
        System.out.println("方法拦截器结束了");
        return result;
    }
    @Override
    public void setExcludeMethods(String excludeMethods) {
        // TODO Auto-generated method stub
        super.setExcludeMethods(excludeMethods);
    }
    @Override
    public void setIncludeMethods(String includeMethods) {
        // TODO Auto-generated method stub
        super.setIncludeMethods(includeMethods);
    }
public void setExcludeMethods(String excludeMethods): 排除需要过滤的方法一设 置方法“黑名单”,  所有在excludeMethods字符串中列出的方法都不会被拦截。
public void setIncludeMethods(String includeMethods):设置需要过滤的方法一设 置方法“白名单”,所有在includeMethods字符串中列出的方法都会被拦截。
//拦截器申明,这里我省略了。
 <interceptor-ref name="MethodInterceptor">
 <param name="excludeMethods">execute</param>
 </interceptor-ref>

这里拦截方法,因为action的执行入口就是execute,所以只有一个execute逻辑处理的方法,这个方法拦截器效果不明显,但是如果两个逻辑处理,就起作用了。

下面,我们在逻辑方法中添加一个show逻辑处理方法和execuete。

 <constant name="struts.enable.DynamicMethodInvocation" value="true"/>  配置动态调用逻辑动态处理的常量。
   <interceptor-ref name="MethodInterceptor">
   <param name="excludeMethods">execute</param>
   <param name="includeMethods">show</param>//拦截多个方法之间,方法名用,分开。
   </interceptor-ref>
   <interceptor-ref name="defaultStack"/>
   <allowed-methods>execute,show</allowed-methods>

这样的话,就可以拦截show方法,而不拦截execute方法。

动态调用处理方法,用!跟上对应的方法名。

http://localhost:9999/ValidateTest/down!show

拦截器执行顺序

   <interceptor-ref name="MyFirstInterceptor">
   <param name="name">第一个拦截器</param>
   </interceptor-ref>
   <interceptor-ref name="MyFirstInterceptor">
   <param name="name">第二个拦截器</param>
   </interceptor-ref>
   <interceptor-ref name="defaultStack"/>

我们对同一个拦截器,多次使用,通过参数name去区分。

public String intercept(ActionInvocation arg0) throws Exception {
        // TODO Auto-generated method stub
        System.out.println(name+"action 开始执行");
        DownAction down = (DownAction) arg0.getAction();//这里可以获取拦截器的action实例
        long start = System.currentTimeMillis();
        String result = arg0.invoke();
        long end = System.currentTimeMillis();
        System.out.println(name+"action 执行时间"+(end-start));
        return result;
    }

可以得出如下结论:在Action的控制方法执行之前,位于拦截器链前面的拦截器将先发生作用;在Action的控制方法执行之后,位于拦截器链前面的拦截器将后发生作用。

拦截结果的监听

在前面的简单拦截器中,我们将在execute 方法执行之前、执行之后的动作都定义在拦截器的intercept(ActionInvocation invocation)方法中,这种方式看上:去结构不够清晰。

为了精确定义在execute方法执行结束后,在处理物理资源转向之前的动作,Struts 2提供了用于拦截结果的监听器,这个监听器是通过手动注册在拦截器内部的。

public class MyPreResultListener  implements PreResultListener {

    /**
     * ActionInvocation 保存了action的引用,但是实际作用是不大,到了获取结果
     * 你还要action引用有啥用
     * String 是返回执行结果代码
     */
    @Override
    public void beforeResult(ActionInvocation arg0, String arg1) {
        // TODO Auto-generated method stub
        System.out.println(arg1);

    }

}

beforeResult 这个方法中,虽然可以获取到action引用,但是不要在该方法中使用invoke,这样会限于死循环,你本来就是execute执行过来,你又执行execute,执行完,要执行,是不是就死循环了。

在拦截器中通过action引用去注册监听器

    arg0.addPreResultListener(new MyPreResultListener());

覆盖拦截器栈中某个拦截器的参数

如果需要在使用拦截器栈时直接覆盖栈内某个拦截器的属性值,则在指定需要被覆盖的属性时,不能只指定属性名,必须加.上该属性属于的拦截名。即采用如下形式: <拦截器名>.<属性名>。

//对于拦截器栈的定义申明,里面是对拦截器的引用

     <interceptor-stack name="mystack">
     <interceptor-ref name="MyFirstInterceptor"></interceptor-ref>
     <interceptor-ref name="MethodInterceptor">
     <param name="name">你好</param>
     </interceptor-ref>
    </interceptor-stack>

使用拦截器

   <interceptor-ref name="mystack">
   <param name="MyFirstInterceptor.name">新的名字</param>
   </interceptor-ref>
相关标签: struts 拦截器