Struts 2(六):拦截器

第一节 拦截器介绍以及实现原理

1.1 拦截器简介

  拦截器是Struts 2的核心组成部分,拦截器的功能是在执行某一个操作时(或调用某个方法时),它会在执行操作前以及执行操作后进行一系列操作。Struts 2的大部分功能都是通过拦截器来完成的,在拦截器中应用了软件开发中的一个重要思想,那就是面向切面编程,也就是AOP。

  Struts 2的拦截器与过滤器Filter非常类似,但是两者拦截的对象不同,拦截器用来拦截业务控制器,也就是说拦截器只能用来拦截使用了该拦截器的Action,而过滤器用来过滤用户请求,对于所有的请求都会进行过滤,如JSP页面、图片文件、CSS文件等

  Struts 2通过一种可插拔式的设计来添加或删除拦截器,从而提供了非常好的可扩展性。通过Struts 2提供的内建拦截器可以完成许多的功能,同时开发人员还可以自定义拦截器从而扩展Struts 2框架。  

 

1.2 拦截器实现原理

  其实所谓的拦截其实就是动态的生成一个代理对象,在这个代理对象中包含了拦截器方法的调用,当调用该代理对象的方法时,同时会调用拦截器中的方法,通过这样的方法就实现了动态调用拦截器方法的目的。

下面这段代码主要演示如何通过动态代理来实现拦截器,从而了解拦截器的实现原理:

复制代码
package com.sanqing.interceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface User {
    public void up();                    //声明搭电梯上楼方法
}
class UserImpl implements User{
    public void up() {
        System.out.println("搭电梯上楼");    //实现搭电梯上楼方法
    }
}
class Elevator {
    public void openDoor() {
        System.out.println("开门");//开门方法
    }
    public void closeDoor() {
        System.out.println("关门");//关门方法
    }
}
class MyHandler implements InvocationHandler {
    private Object user;//被代理目标对象
    Elevator ele = new Elevator();//电梯类实例
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result;        //结果对象
        ele.openDoor();        //调用电梯类的开门方法
        result = method.invoke(user, args);//执行用户方法
        ele.closeDoor();    //调用电梯类的关门方法
        return result;        //返回结果对象
    }
    public void setUser(Object user){    //设置目标对象
        this.user = user;
    }
}
class ProxyFac {
    public static Object getProxy(Object user) {
        MyHandler mh = new MyHandler();//创建处理类实例
        mh.setUser(user);//传入user实例
        //返回代理类实例
        return Proxy.newProxyInstance(UserImpl.class.getClassLoader(), UserImpl.class.getInterfaces(), mh);
    }
}
public class MyInterceptor {
    public static void main(String[] args) {
        User user = new UserImpl();//创建目标对象,用来代理
        User proxyUser = (User) ProxyFac.getProxy(user);//通过代理对象获得代理实例
        proxyUser.up();//调用代理实例的上楼方法
    }
}
复制代码

 

第二节 自定义拦截器

2.1 通过Interceptor接口实现拦截器

2.2 通过AbstractInterceptor类实现拦截器

2.3 配置拦截器

  在配置文件struts.xml的package节点下添加一个interceptors节点,该节点下可以包含多个interceptor子节点,每个interceptor子节点用来配置一个拦截器,通过interceptor节点指定该拦截器的名称和实现类来完成拦截器配置,代码格式如下:

<interceptors>
    <interceptor name="拦截器名称" class="拦截器实现类"></interceptor>
</interceptors>

 

2.4 使用拦截器

  上一小节介绍了如何配置拦截器,但是仅经过上述步骤拦截器还不能起作用,因为业务控制器Action还不知道要使用哪个拦截器,需要在Action元素中添加interceptor-ref节点来指定使用哪个拦截器,代码示例如下:

复制代码
<?xml version="1.0" encoding="UTF-8" ?><!-- XML声明 -->
<!DOCTYPE struts PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
 "http://struts.apache.org/dtds/struts-2.1.dtd"><!-- 指定Struts 2配置文件的DTD信息 -->
<struts><!-- 根节点 -->
    <package name="struts2" extends="struts-default">
      <interceptors>
          <interceptor name="myInterceptor" class="com.sanqing.interceptor.MyInterceptor2"></interceptor>
      </interceptors>    
      <action name="register" class="com.sanqing.action.RegisterAction">
          <result name="success">/ShowUserInfo.jsp</result>
          <interceptor-refname="myInterceptor"></interceptor-ref>
      </action>
    </package>    
</struts>
复制代码

 

2.5 使用默认拦截器

  Struts 2里面的Action在没有配置拦截器时,实际上还是有默认的拦截器在工作,默认情况下是使用defaultStack这个拦截器栈,一旦为某个Action添加了自定义拦截器,就必须为该Action配置默认拦截器栈defaultStack,一般是在<action>节点中通过<interceptor-ref>节点引用默认拦截器栈,通常将defaultStack配置在自定义拦截器之后,这样就能保证业务控制器首先被自定义拦截器拦截,配置代码如下:

<action name="register" class="com.sanqing.action.RegisterAction">
    <result name="success">/ShowUserInfo.jsp</result>
    <interceptor-ref name="myInterceptor"></interceptor-ref>
    <interceptor-ref name="defaultStack"></interceptor-ref>
</action>

 

第三节 深入了解拦截器

3.1 为拦截器传入参数

  可以通过两种方式为拦截器传入参数,一种是在配置拦截器时配置参数,一种是在使用拦截器时配置参数。要为拦截器传入参数,拦截器就必须能接受参数,下面来定义一个拦截器,能够接受参数,并对参数进行处理:

复制代码
package com.sanqing.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor3 extends AbstractInterceptor{
    private String interceptorName;        //名称属性
    public void setInterceptorName(String interceptorName) {//设置名称属性
        this.interceptorName = interceptorName;
    }
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println(interceptorName + ":拦截前操作");    //拦截前执行操作
        String result = invocation.invoke();                //向下传递
        System.out.println(interceptorName + ":拦截后操作");    //拦截后执行操作
        return result;                                        //返回结果
    }
}
复制代码

(1)在配置拦截器时配置参数

<interceptor name="myInterceptor3" class="com.sanqing.interceptor.MyInterceptor3">
    <param name="interceptorName">配置拦截器时配置参数</param>
</interceptor>

(2)在使用拦截器时配置参数

<action name="register" class="com.sanqing.action.RegisterAction">
    <result name="success">/ShowUserInfo.jsp</result>
    <interceptor-ref name="myInterceptor3">
        <param name="interceptorName">使用拦截器时配置参数</param>
    </interceptor-ref>
</action>

注:在配置和使用拦截器时都可以为其配置参数,但是如果两者都使用的话,后者会将前者的参数值给覆盖,推荐使用在配置拦截器时配置参数,这样配置的参数是公用的,在所有Action中的使用只需配置一次,至于在使用拦截器时配置参数,只有在某些个别情况下使用拦截器时再为其配置参数,从而覆盖前面配置的默认值。

3.2 配置拦截器栈

(1)下面这段代码主要演示如何配置拦截器栈,并在业务控制器中使用拦截器栈

复制代码
<interceptors>
    <interceptor name="myInterceptor2" class="com.sanqing.interceptor.MyInterceptor2"></interceptor>
    <interceptor name="myInterceptor3" class="com.sanqing.interceptor.MyInterceptor3"></interceptor>
    <interceptor-stack name="myInterceptorStack">
        <interceptor-ref name="myInterceptor2"></interceptor-ref>
        <interceptor-ref name="myInterceptor3"></interceptor-ref>
    </interceptor-stack>
</interceptors>
<action name="register" class="com.sanqing.action.RegisterAction">
    <result name="success">/ShowUserInfo.jsp</result>
    <interceptor-ref name="myInterceptorStack"></interceptor-ref>
</action>
复制代码

 

(2)在前面的配置中,我们一般都是在<action>节点中单独引入Struts 2的默认拦截器栈defaultStack,其实完全可以将其加入到自定义的拦截器栈中,将默认拦截器栈defaultStack加入到自定义的拦截器栈中,使用起来更加方便,不用再为多个Action重复配置该默认拦截器栈,配置代码如下:

<interceptor-stack name="myInterceptorStack">
    <interceptor-ref name="myInterceptor2"></interceptor-ref>
    <interceptor-ref name="myInterceptor3"></interceptor-ref>
    <interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>

 

(3)在拦截器栈中引入拦截器时,可以为拦截器配置参数,配置代码如下:

<interceptor-stack name="myInterceptorStack">
    <interceptor-ref name="myInterceptor2"></interceptor-ref>
    <interceptor-ref name="myInterceptor3">
        <param name="interceptorName">引用时配置参数</param>
    </interceptor-ref>
    <interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>

 

3.3 覆盖拦截器栈中指定拦截器的参数

前面介绍了在使用拦截器时可以为拦截器指定参数,同样在使用拦截器栈时也可以为拦截器指定参数,从而覆盖在配置拦截器栈时指定的参数值,在Action节点下的interceptor-ref节点中通过添加param节点来添加参数,并指定参数名和参数值,代码如下所示:

<action name="register" class="com.sanqing.action.RegisterAction">
    <result name="success">/ShowUserInfo.jsp</result>
    <interceptor-ref name="myInterceptorStack">
        <param name="myInterceptor3.interceptorName">使用拦截器栈</param>
    </interceptor-ref>
</action>

 

3.4 拦截器执行顺序

拦截器执行顺序规则如下:

(1)在拦截器中先引入的拦截器会先执行,后引入的拦截器会后执行;

(2)一个拦截器执行完其拦截前操作后,会传递给下一个拦截器(如果有多个拦截器的话)或者Action;

(3)当一个拦截器的拦截后操作执行完后,会返回其上一个拦截器,继续执行上一个拦截器的拦截后操作。

根据第2点和第3点规则绘制的拦截器执行流程图如下图所示:

 

第四节 Struts 2内建拦截器

4.1 内建拦截器介绍

4.2 内建拦截器的配置

 

posted @   时空穿越者  阅读(161)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示