Struts2的拦截器

1. 什么是拦截器

拦截器,用于在某个方法或字段被访问之前进行拦截,然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。拦截器是动态拦截Action调用的对象,它提供了一种机制使开发者可以在一个Action执行的前后执行自己编写的代码,也可以在一个Action执行前阻止其执行,同时也是提供了一种可以提取Action中可重用的部分的方式。

拦截器链(Interceptor Chain,在Struts2中称为拦截器栈Interceptor Stack),拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的前端控制器时,Struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

总结:Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链,在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

2. Struts2的执行流程

在这里插入图片描述

3. 拦截器的定义

在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。该接口中定义的代码如下:

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

该接口提供了三个方法:

  • void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。
  • void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。
  • String intercept(ActionInvocation invocation) throws Exception:该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。

除了实现Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter。该类实现了Interceptor接口,并且提供了init()方法和destroy()方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。AbstractInterceptor类已经实现了Interceptor接口的所有方法,一般情况下,只需继承AbstractInterceptor类,实现interceptor()方法就可以创建自定义拦截器。只有当自定义的拦截器需要打开系统资源时,才需要覆盖AbstractInterceptor类的init()方法和destroy()方法。与实现Interceptor接口相比,继承AbstractInterceptor类的方法更为简单

4. 拦截器的配置

  • 拦截器
    要想让拦截器起作用,首先要对它进行配置。拦截器的配置是在struts.xml文件中完成的,它通常以<interceptor>标签开头,以</interceptor>标签结束。定义拦截器的语法格式如下:

    <interceptor name="interceptorName" class="interceptorClass">
    	<param name="paramName">paramValue</param>
    </interceptor>
    

    上述语法格式中,name属性用来指定拦截器的名称,class属性用于指定拦截器的实现类。有时,在定义拦截器时需要传入参数,这时需要使用<param>标签,其中name属性用来指定参数的名称,paramValue表示参数的值。

  • 拦截器栈
    在实际开发中,经常需要在Action执行前同时执行多个拦截动作,如:用户登录检查、登录日志记录以及权限检查等。这时,可以把多个拦截器组成一个拦截器栈,在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。

    定义拦截器栈使用<interceptors>元素和<interceptor-stack>子元素,当配置多个拦截器时,需要使用<interceptor-ref>元素来指定多个拦截器,配置语法如下:

    <interceptors>
    	<interceptor-stack name="interceptorstackName">
    		<interceptor-ref name="interceptorName1"/>
    		<interceptor-ref name="interceptorName2"/>
    	</interceptor-stack>
    </interceptors>
    

    在上述语法中,interceptorStackName值表示配置的拦截器栈的名称,interceptorName值表示拦截器的名称。除此之外,在一个拦截器栈中还可以包含另一个拦截器栈,示例代码如下:

    <package name="default" namespace="/" extends="struts-default"> 
    	<interceptors>
    		<!-- 声明拦截器 --> 
    		<interceptor name="interceptorl" class="interceptorClass"/> 
    		<interceptor name="interceptor2" class="interceptorClass"/> 
    		
    		<!-- 定义一个拦截器栈 mystack,该拦截器栈中包含两个拦截器和一个拦截器栈 --> 
    		<interceptor-stack name="mystack"> 
    			<interceptor-ref name="interceptorl"/> 
    			<interceptor-ref name="interceptor2"/> 
    			<interceptor-ref name="defaultStack"/> 
    		</interceptor-stack> 
    	</interceptors> 
    </package>
    

    在上述代码中,定义的拦截器栈是myStack,在myStack栈中,除了引用了两个自定义的拦截器interceptor1和interceptor2外,还引用了一个内置拦截器栈defaultStack(这个拦截器是struts2的内置拦截器栈,是必须要引入的)。

5. 自定义拦截器案例

public class LoginInterceptor extends MethodFilterInterceptor {

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
	
		//获得session
		Map<String, Object> session = ActionContext.getContext().getSession();
		//获得登陆标识
		Object object = session.get("user");
		//判断登陆标识是否存在
		if(object == null){
			//不存在 -> 没登录 -> 重定向到登录页面
			return "toLogin";
		}else{
			//存在 -> 已经登陆 -> 放行
			return invocation.invoke();
		}
		
	}

}
<struts>
	<package name="demo1" namespace="/" extends="struts-default" >
		<interceptors>
			<!-- 注册拦截器 -->
			<interceptor name="loginInterceptor" class="cn.joker.interceptor.LoginInterceptor"></interceptor>
			<!-- 注册拦截器栈 -->
			<interceptor-stack name="myStack">
				<interceptor-ref name="loginInterceptor">
					<!-- 指定哪些方法不拦截 -->
					<param name="excludeMethods">login</param>
					<!-- 指定哪些方法需要拦截 -->
					<param name="includeMethods">find,add,update,delete</param>
				</interceptor-ref>
				
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<!-- 指定包中的默认拦截器栈 -->
		<default-interceptor-ref name="myStack"></default-interceptor-ref>
		
		<action name="CustomerAction_*" class="cn.joker.action.CustomerAction" method="{1}" >
			<result name="toLogin" >/login.jsp</result>
			<result name="success" >/hello.jsp</result>
		</action>
	</package>
</struts>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值