Struts2拦截器介绍

Interceptor拦截器类似于过滤器,是可以在action执行前后执行的代码。是我们做web开发时经常用的技术。比如:权限控制、日志等。我们也可以将多个Interceptor连在一起组成Interceptor栈。
在这里插入图片描述
拦截器的工作原理如上图,每一个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)提供的拦截器的功能说明


在这里插入图片描述

自定义拦截器

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

拦截器必须是无状态的,不要使用在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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值