为什么会有拦截器:
许多Action都需要做一些相同的事情,比如说登录验证,表单输入验证,上传文件时的初始化操作,而有些Action则需要在页面显示前做一些预先填充数据的准备,这些需求在项目中都是很常见的,设想一下,如果在每个action都做一些重复性的功能逻辑,这样实现即繁琐,又违背了软件复用的思想,所以为了解决这个问题,Struts2的设计者们把这些共有的逻辑独立出来,实现成一个个的拦截器,拦截器由此而诞生。
什么是拦截器:
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作,拦截是AOP的一种实现策略。
谈到拦截器,还有一个词需要提一下——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用,访问完之后,拦截器链中的拦截器就会按其之前定义的顺序被逆序调用。
理解拦截器:
拦截器是在某个Action被调用之前与之后执行的,许多框架的核心功能都实现为拦截器,如重复提交,类型转换,校验,文件上传等等,这些实现多亏了拦截器才得以简单实现,每个拦截器都是可插拔的,所以你可以精确为某个需要某种功能的Action配置相应的拦截器。
可以为每个Action配置拦截器,用户自定义的拦截器可以与框架附带的拦截器混合搭配使用,拦截器会在Action执行前做很多繁琐的事情,这样就避免了在每个Action中出现重复代码。
下面是Action的生命周期图:
从图中可以看出Struts2的Interceptor一层一层把Action包裹在最里面,所有的用户请求都会被拦截器所拦截,然后交给Action处理,处理结果以逻辑视图方式返回给用户。而这个调用执行流程,是由Struts 2的配置文件来实现的。可以定义一个拦截器栈为多个拦截器指定执行顺序,在某些时候,拦截器栈中的拦截器的执行顺序是非常重要的。
每个位于堆栈中的Interceptor,除了需要完成它自身的逻辑,还需要完成一个特殊的执行职责。这个执行职责有3种选择:
1) 中止整个执行,直接返回一个字符串作为resultCode
2) 通过递归调用负责调用堆栈中下一个Interceptor的执行
3) 如果在堆栈内已经不存在任何的Interceptor,调用Action
Struts2的拦截器结构的设计,实际上是一个典型的责任链模式的应用。首先将整个执行划分成若干相同类型的元素,每个元素具备不同的逻辑责任,并将他们纳入到一个链式的数据结构中(我们可以把堆栈结构也看作是一个递归的链式结构),而每个元素又有责任负责链式结构中下一个元素的执行调用。
拦截器都是通过代理的方式调用的,当用户请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(List),然后逐个地调用列表中的拦截器,拦截器时序图如下图所示。
从上图中可以看出,拦截器的执行顺序是:
在Action之前,拦截器的执行顺序与堆栈中定义的一致;而在Action和Result之后,拦截器的执行顺序与堆栈中定义的顺序相反。这就好比我们穿衣服一样,早上起床一件一件的套在身上,晚上睡觉前,再一件一件的脱下来。
配置拦截器:
<interceptors> <interceptor name="拦截器名" class="拦截器对应的类" /> <interceptor-stack name="拦截器栈名"> <interceptor-ref name="拦截器名或拦截器栈名1" /> <interceptor-ref name="拦截器名或拦截器栈名2" /> </interceptor-stack> </interceptors>
引用拦截器:
<action name="Action的名称" class="Action对应的类"> <result name="success">视图资源</result> <!-- 使用拦截器,一般配置在result之后, --> <interceptor-ref name="拦截器名或拦截器栈名" /> </action>
此处需要注意的是,如果为Action指定了一个拦截器,则系统默认的拦截器栈将会失去作用。为了继续使用默认拦截器,我们可以在配置文件中手动引入默认拦截器。
<action name="Action的名称" class="Action对应的类"> <result name="success">视图资源</result> <!-- 使用拦截器,一般配置在result之后, --> <interceptor-ref name="defaultStack"/> <interceptor-ref name="拦截器名或拦截器栈名" /> </action>
需要把默认的拦截器放在自定义的拦截器前面,否则会出错。
如果不想为每个Action都配置相同的拦截器或拦截器栈,则可以在配置文件中定义一个默认的拦截器或拦截器栈
<!-- 这句是设置所有Action自动调用的拦截器堆栈 --> <default-interceptor-ref name="拦截器名或拦截器栈名" /> <action name="Action的名称1" class="Action对应的类1" /> <action name="Action的名称2" class="Action对应的类2" />
注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用。
自定义拦截器:
自定义一个拦截器需要三步:
1 、自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
2、在strutx.xml中注册上一步中定义的拦截器。
3 、在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。
所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor。该接口提供了三个方法:
1) void init(); 在该拦截器被初始化之后,在该拦截器执行拦截之前,系统回调该方法。对于每个拦截器而言,此方法只执行一次。
2) void destroy();该方法跟init()方法对应。在拦截器实例被销毁之前,系统将回调该方法。
3) String intercept(ActionInvocation invocation) throws Exception; 该方法是用户需要实现的拦截动作。该方法会返回一个字符串作为逻辑视图。
除此之外,继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor是更简单的一种实现拦截器类的方式,因为此类提供了init()和destroy()方法的空实现,这样我们只需要实现intercept方法。
下面是一个用于验证是否登录的拦截器:
package com.struts.interceptor; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class PermissionInterceptor implements Interceptor { private static final long serialVersionUID = -1615930166094288049L; public void destroy() { } public void init() { } public String intercept(ActionInvocation invocation) throws Exception { ActionContext ac = ActionContext.getContext(); Object name = ac.getSession().get("user"); if (name != null) { return invocation.invoke(); // 返回代表视图的字符串,如果还有拦截器则继续执行 } else { return "error"; } } }
简陋的不能在简陋的登陆页面login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登录页面</title> </head> <body> <% request.getSession().setAttribute("user", "jetty"); %> 用户登录 </body> </html>
如果用户访问过该页面,则在session域中存放键为user,值为jetty的键值对。
下面是配置文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="struts" namespace="/test" extends="struts-default"> <interceptors> <!-- 自定义拦截器 --> <interceptor name="permissionInterceptor" class="com.struts.interceptor.PermissionInterceptor" /> <interceptor-stack name="permissionStack"> <!-- 默认的拦截器栈,定义在struts2-core-2.3.8.jar的struts-default.xml中, 因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的, 所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。--> <interceptor-ref name="defaultStack" /> <interceptor-ref name="permissionInterceptor" /> </interceptor-stack> </interceptors> <global-results> <result name="error">/WEB-INF/pages/error.jsp</result> </global-results> <action name="view" class="com.struts.action.ViewInfoAction" method="execute"> <!-- 引用拦截器 --> <interceptor-ref name="permissionStack" /> <result name="success">/WEB-INF/pages/viewinfo.jsp</result> </action> </package> </struts>
简单的Action:
package com.struts.action; public class ViewInfoAction { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String execute() { this.message = "Hello, my name is Jetty"; return "success"; } }
如果用户没有访问过login.jsp,而直接访问名称为view的action,则会跳转到error.jsp
简单的error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>提示信息页面</title> </head> <body> 您没有权限查看该页面,请登录后查看! </body> </html>
如果用户访问过login.jsp,则用户访问名称为view的action时,会跳转到viewinfo.jsp
简单的viewinfo.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>信息</title> </head> <body> ${message } </body> </html>
即可以在浏览器中看到Hello, my name is Jetty信息。
注:Struts2默认的拦截器栈,定义在struts2-core-2.x.x.jar的struts-default.xml中
相关推荐
JSP 开发之Struts2内建自定义拦截器.docx
http://blog.csdn.net/zhiweiv/archive/2008/09/19/2954047.aspx
Struts2全局、局部自定义拦截器源码。
strut2 配置自定义拦截器 包括struts2.xml 和 action对应的xml 以及拦截器 可能有点简单 但是基本配置都有
简单的struts2自定义拦截器 很适合web初学者
Struts2_自定义拦截器 struts2_3500_my_interceptor
通过struts2来自定义一个拦截器,需要定义struts2.xml和web.xml文件,详细代码见下载。
JSP 开发之Struts2内建自定义拦截器 Struts2的自定义拦截器主要用于解析请求参数,将请求参数赋值给Action属性,执行数据校验,文件上传等等操作。当需要扩展Struts2的...--配置自定义拦截器--> <interceptor n
部署自定义拦截器!! --> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack" /> <interceptor-ref name="custom" /> </interceptor-stack> <result>/MyJsp.jsp <!--...
struts2自定义拦截器.pdf
struts2的自定义拦截器代码
自定义拦截器的实现以及拦截器的详细配置,配置文件里面有特别详细的注释,希望对刚接触拦截器的同学有帮助
struts2的自定义拦截器代码例子
myeclipse平台下使用struts2.3框架搭建实例,理解struts2工作原理,了解struts2自定义类型转换,自定义拦截器,掌握struts2的mvc框架应用
由于struts2标签的性能不好,项目组决定不使用,但是如果用struts2自带的拦截器防止重复提交又必须struts标签,所以只好自定拦器实现
NULL 博文链接:https://llxhna.iteye.com/blog/1067851
struts2的一个简单的拦截器例子