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

Struts2拦截器介绍

程序员文章站 2022-07-09 17:16:07
...

Interceptor拦截器类似于过滤器,是可以在action执行前后执行的代码。是我们做web开发时经常用的技术。比如:权限控制、日志等。我们也可以将多个Interceptor连在一起组成Interceptor栈。
Struts2拦截器介绍
拦截器的工作原理如上图,每一个Action请求都包装在一系列的拦截器的内部。拦截器可以在Action执行直线做相似的操作也可以在Action执行直后做回收操作。

每一个Action既可以将操作转交给下面的拦截器,Action也可以直接退出操作返回客户既定的画面。

Struts2拦截器,每个拦截器类只有一个对象实例,即采用单例模式,所以引用这个拦截器的Action都共享这一拦截器类的实例,因此,在拦截器中如果使用类变量,要注意同步问题。

实现原理 : Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对应拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

最基本的bean的注入就是通过默认的拦截器实现的,一般在struts2.xml的配置中,package内直接或间接继承了struts-default.xml,这样struts2默认的拦截器就会作用。

拦截器和过滤器的区别

  1. 拦截器和过滤器的概念非常类似。

  2. 过滤器隶属于web容器,可以过滤一切请求(包括action、servlet、jsp、html等等)。

  3. 而拦截器隶属于struts2框架,只能拦截action(无法拦截对jsp的请求)。

  4. 过滤器内部采用函数回调来实现。拦截器采用动态代理来实现。

拦截器在struts2中的应用

对于Struts2框架而言,正是大量的内置拦截器完成了大部分操作。比如:

– params拦截器将http请求中参数解析出来赋值给Action中对应的属性。
– Servlet-config拦截器负责把请求中HttpServletRequest实例和HttpServletResponse实例传递给Action
– …

struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。

附:Struts2(XWork)提供的拦截器的功能说明
Struts2拦截器介绍
Struts2拦截器介绍
Struts2拦截器介绍

自定义拦截器

在开始着手创建自定义拦截器前,切记以下原则:

拦截器必须是无状态的,不要使用在API提供的ActionInvocation之外的任何东西。要求拦截器是无状态的原因是Struts 2不能保证为每一个请求或者action创建一个实例,所以如果拦截器带有状态,会引发并发问题。

如何自定义拦截器?

  1. 实现接口Interceptor或者继承类AbstractInterceptor ,并重写public String intercept(ActionInvocation invocation) 。
  2. 在sturts.xml中使用<interceptor>元素来定义拦截器 。
  3. 在配置action时使用<interceptor-ref>元素来使用拦截器。

注意:如果为Action指定了一个拦截器,则系统默认的拦截器栈将会失去作用。为了继续使用默认拦截器,所以配置文件中需要手动引入默认拦截器(见示例)。

另外,可以将多个拦截器合并在一起作为一个堆栈调用,当一个拦截器堆栈被附加到一个Action的时候,要想Action执行,必须执行拦截器堆栈中的每一个拦截器(见示例)。

Interceptor接口声明了三个方法:

public interface Interceptor extends Serializable {
 
    void destroy();
 
    void init();
 
    String intercept(ActionInvocation invocation) throws Exception;
}

Init方法在拦截器类被创建之后,在对Action镜像拦截之前调用,相当于一个post-constructor方法,使用这个方法可以给拦截器类做必要的初始话操作。

Destroy方法在拦截器被垃圾回收之前调用,用来回收init方法初始化的资源。

Intercept是拦截器的主要拦截方法,如果需要调用后续的Action或者拦截器,只需要在该方法中调用invocation.invoke()方法即可,在该方法调用的前后可以插入Action调用前后拦截器需要做的方法。如果不需要调用后续的方法,则返回一个String类型的对象即可,例如Action.SUCCESS,在struts.xml中配置相应的result标签,控制返回视图。

另外AbstractInterceptor提供了一个简单的Interceptor的实现,这个实现为:

public abstract class AbstractInterceptor implements Interceptor {
 
     public void init() {
    }
   
    public void destroy() {
    }
 
 
    public abstract String intercept(ActionInvocation invocation) throws Exception;
}

在不需要编写init和destroy方法的时候,只需要从AbstractInterceptor继承而来,实现intercept方法即可。

示例

考虑如下需求:在实现商城购物时,我们希望用户在登陆之后才能够进行商品的浏览、添加购物车等操作,在未登录状态下点击购物车等页面会跳转到登录界面让用户登录。

使用拦截器的解决思路:在用户登录之后,User对象存放在Session当中,未登录时Session中不存在User对象。故在拦截器中可判断Session中是否存在User对象,不存在则返回登录视图,存在则执行invoke方法,即请求会被action正常响应,并返回相应的结果。

1.编写Interceptor类

public class LoginInterceptor extends AbstractInterceptor{

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		Map<String, Object> session = invocation.getInvocationContext().getSession();
		User user=(User)session.get("user");
		if(user==null)	{
			System.out.println("请先登录!");
			return "login";
		}
		return invocation.invoke();
	}
}

2.在struts.xml中注册拦截器

<package name="interceptor" extends="struts-default" namespace="/">
		<interceptors>
			<interceptor name="doLoginInterceptor" class="com.xintao.learnContext.interceptor.LoginInterceptor"/>
			<interceptor-stack name="loginInterceptor">		<!--拦截器栈-->
				<interceptor-ref name="doLoginInterceptor"/>
				<interceptor-ref name="defaultStack"/>		<!--引入默认拦截器-->
			</interceptor-stack>
		</interceptors>
</package>

3.在对应的action中使用<interceptor-ref>标签使用拦截器

<package name="learnContext" extends="interceptor" namespace="/">
		<action name="welcome" class="com.xintao.learnContext.controller.LoginAction" method="welcome">
			<interceptor-ref name="loginInterceptor"/>
			<result name="login">/login.jsp</result>
			<result name="welcome">/welcome.jsp</result>
		</action>
</package>

上述步骤是将拦截器及拦截器栈声明为了全局变量,注意在第3步中,action的package中的extends元素不再是“struts-default”,变为其引用的拦截器,该拦截器所在package名称。

也可在action中声明拦截器,第一步与上述方法相同,第2、3步可合在一个package中书写。

另一种struts.xml配置方法(较常用):

<package name="learnContext" extends="struts-default" namespace="/">
		<interceptors>
			<interceptor name="doLoginInterceptor" class="com.xintao.learnContext.interceptor.LoginInterceptor"/>
			<interceptor-stack name="loginInterceptor">
				<interceptor-ref name="doLoginInterceptor"/>
				<interceptor-ref name="defaultStack"/>
			</interceptor-stack>
		</interceptors>
		
		<action name="welcome" class="com.xintao.learnContext.controller.LoginAction" method="welcome">
			<interceptor-ref name="loginInterceptor"/>
			<result name="welcome">/welcome.jsp</result>
			<result name="login">/login.jsp</result>
		</action>
		
</package>

注意事项

1.interceptor-ref内可以定义param元素,即实现对特定方法的拦截;但是注意,使用方法拦截器必须直接或间接实现AbstractInerceptor接口或者继承MethodFilterInterceptor类,并重写doIntercept方法.param标签内有两个属性:

excludeMethods:排除的方法
includeMethods:包含的方法

2.每一个拦截器都可以配置参数,有两种方式配置参数,一是针对每一个拦截器定义参数,二是针对一个拦截器堆栈统一定义所有的参数,例如:

<interceptor-ref name="validation">
 <param name="excludeMethods">myValidationExcudeMethod</param>
</interceptor-ref>
<interceptor-ref name="workflow">
 <param name="excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>

或者

<interceptor-ref name="defaultStack">
    <param name="validation.excludeMethods">myValidationExcludeMethod</param>
    <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>

参考:
https://www.cnblogs.com/yw-ah/p/5761235.html
https://www.cnblogs.com/withyou/p/3170440.html