浅谈struts2拦截器

1、定义拦截器。
Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor 接口
。该接口声明了3个方法,

void  init();
void  destroy();
String intercept(ActionInvocation invocation) 
throws  Exception;

其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml 中声明了该拦截器就会被执行。
intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑。

不过,struts中又提供了几个抽象类来简化这一步骤。
public abstract class AbstractInterceptor implements Interceptor;
public abstract class MethodFilterInterceptor extends AbstractInterceptor;
都是模板方法实现的。
其中AbstractInterceptor 提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;
MethodFilterInterceptor 则提供了includeMethods和excludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。

一般来说,拦截器的写法都差不多。看下面的示例:

 

public   class  AuthInterceptor  extends  MethodFilterInterceptor {
    
protected  String doIntercept(ActionInvocation invocation)  throws  Exception  {        
        Map session 
=  invocation.getInvocationContext().getSession();
        
// 如果session中存在username字段,且传入Action实现了Authenticatable接口,且验证成功
        
// 当然这里只是举例子,具体要根据业务逻辑来写
         if (session.containsKey( " username " ) &&  (invocation  instanceof  Authenticatable)
               
&&  ((Authenticatable)invocation).validate((String)session.get( " username " ),(String)session.get( " password " ))) {
            
// 将数据流转给真正的Action
             return  invocation.invoke();
        }
else {
            
// 返回一个全局登录失败的result
             return  Action.LOGIN;
        }

    }

}

其中,if()逻辑内执行了从session中取用户信息及验证的逻辑,如果成功,则调用invocation.invoke()将逻辑交给Action,否则退出并返回一个全局的Login结果。


2.声明拦截器
拦截器需要在struts.xml中声明。在说明步骤之前,先介绍一下struts中拦截器的框架。

在struts中拦截器实际上分为拦截器和拦截器栈,拦截器栈可以包含一到多个拦截器或者拦截器栈。从上层看来,拦截器和拦截器栈实际上没有什么区别(就像操作系统中的文件夹和文件)。struts在入口处递归的调用了<default-interceptor-ref> 中定义的拦截器(栈)中的所有拦截器。

其实之前如果看过struts-default.xml 的话,可以看到struts中内建了许多的拦截器,事实上,即便我们在struts.xml 中什么都不声明,程序也会在后台执行缺省拦截器栈中定义的许多拦截器逻辑,比如说将页面上的field映射到对应Action的同名属性中、自动执行类型转换、自动关联验证xml等等。这些拦截器会在每个没有显式声明拦截器的Action执行前后被执行。

需要注意的是,正如上面一句所提到的,如果在Action中显式声明了一个拦截器,那么系统默认的拦截器将不会被调用。因此,如果直接将自定义的拦截器放入Action中的话,内建的那些拦截器将会被忽略,这会导致错误。所以我们需要在struts.xml<package> 元素下覆盖缺省拦截器。像下面这样:

 

< interceptors >
            
< interceptor-stack  name ="default-with-my-inteceptor" >
                
< interceptor-ref  name ="defaultStack" />
                
< interceptor-ref  name ="XXX-interceptor" />
            
</ interceptor-stack >
            
< interceptor  name ="XXX-interceptor"  class ="com.dev.interceptors.XXXInterceptor"   />
</ interceptors >

< default-interceptor-ref  name ="default-with-my-inteceptor" />

 

这样就将自定义拦截器加上了struts缺省拦截器形成新的缺省拦截器。

因为全局定义了拦截器,虽然拦截器在通过拦截的情况下会返回特定Action的result,但有时候比如权限验证失败等情况下,自定义拦截器会返回自定义的结果,不属于任何特定Action,所以我们也需要定义一个全局result用以响应这个拦截器的返回值。
紧挨在<default-interceptor-ref> 元素下面添加

< global-results >
    
< result  name =""  type ="redirectAction" > global_error.jsp </ result >
</ global-results >


注意到其result type为redirectAction重定向Action,这样struts将以重定向方式处理该Action,并跳转到 global_error.jsp而不会显示出最后一次执行的Action名字。顺便,Action的result缺省是以dispatcher也就是请 求转发的方式处理的。

同时,按照业务逻辑,有些特定Action是不能执行自定义拦截器的。比如说,如果我们定义了一个全局的拦截器,它从session中 取出用户名和密码进行验证,验证通过则继续,不通过则返回到login.jsp页面,那么很显然login.jsp页面提交的那个Action本身是不能 使用该拦截器的,否则就没有地方可以将用户信息放入session了。
这种情况下,就要借助之前提到的“特定Action中定义的拦截器会覆盖全局设置”这个特性了。在需要屏蔽该拦截器的个别Action中显式的声明 defaultStack拦截器(也就是struts内建的拦截器栈),这样,自定义拦截器在这个Action中就不会生效了。


小结一下:
写了这么多,其实大部分都在讲原理,如果理解了原理,这几部做起来是否常容易的。所以重要的是掌握原理。
回忆一下,真正要做的只有三个地方:
(1)写一个拦截器类(实现接口也好,继承抽象类也好)
(2)修改struts.xml声明新的缺省拦截器栈和全局result
(3)对于特定Action,显式声明defaultStack拦截器以屏蔽自定义拦截器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值