1、定义拦截器。
Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor 接口
。该接口声明了3个方法,
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
其中,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来加入或者排除需要过滤的方法。
一般来说,拦截器的写法都差不多。看下面的示例:
![](https://i-blog.csdnimg.cn/blog_migrate/1fa987a29c6482f53d401256f96355eb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ca75c07623e1b494fee67e8f316fc310.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9b8a8a44dd1c74ae49c20a7cd451974e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3c6cafce68eb941a00f1998f1d3d3aa6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9b8a8a44dd1c74ae49c20a7cd451974e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3c6cafce68eb941a00f1998f1d3d3aa6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9b8a8a44dd1c74ae49c20a7cd451974e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/97e794c86028c5f5b5461ae5ef440a4c.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3c6cafce68eb941a00f1998f1d3d3aa6.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/9b8a8a44dd1c74ae49c20a7cd451974e.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/d18c02628675d0a2c816449d98bda930.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/ecedf933ec37d714bd4c2545da43add2.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8f1ba5b45633e9678d1db480c16cae3f.gif)
其中,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> 元素下覆盖缺省拦截器。像下面这样:
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
这样就将自定义拦截器加上了struts缺省拦截器形成新的缺省拦截器。
因为全局定义了拦截器,虽然拦截器在通过拦截的情况下会返回特定Action的result,但有时候比如权限验证失败等情况下,自定义拦截器会返回自定义的结果,不属于任何特定Action,所以我们也需要定义一个全局result用以响应这个拦截器的返回值。
紧挨在<default-interceptor-ref> 元素下面添加
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4f1150b881333f12a311ae9ef34da474.gif)
注意到其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拦截器以屏蔽自定义拦截器