学习内容 拦截器工作原理
Struts 2自带拦截器
自定义拦截器
能力目标
熟悉Struts 2拦截器工作原理
熟练使用和配置拦截器
本章简介
上一章我们深入学习了Struts 2框架的配置,包括Action的配置、Result的配置等等,使我们对Struts 2框架有了更深的了解。Struts 2的核心包括Action、Result和拦截器。拦截器是Struts 2的一个重要特性,实际上Struts 2框架的核心功能都是由拦截器负责完成的。
拦截器(Interceptor)能动态拦截Action调用的对象。它提供了一种机制使开发者可以在一个Action执行之前或执行之后插入需要的代码,同时它也是提供了一种可以提取Action中可重用代码的方式。本章将重点学习Struts 2拦截器。
核心技能部分
5.1 Struts 2的拦截器在第五章学习Struts 2体系结构时已经提到了拦截器,它主要出现在Action执行之前或执行之后,大家可以先回顾一下。对于Web应用程序来说,有很多的业务都是通用的,例如对请求数据的封装、数据的校验、防止表单重复提交等。早期的MVC框架将这些业务功能都写死在核心控制器中了,这直接导致框架的灵活性和可扩展性严重下降。
Struts 2将它的核心功能放到拦截器中实现而不是集中在核心控制器里,并且每个拦截器完成一个业务功能,不同的拦截器还能自由组合,这使得开发人员能够更加高效、灵活的使用Struts 2框架进行开发。
拦截器是动态拦截Action调用的对象,拦截器的方法可以在Action执行之前或之后自动执行,从而将通用的操作动态地插入到Action执行的前后,这跟我们平时组装电脑很类似,业务功能变成了可插拔式,需要哪个功能就“插入”一个拦截器,不需要就“拔出”,非常有利于系统的解耦。
单一的拦截器还可以灵活的组合在一起构成拦截器栈。拦截器是一个类,通过在struts.xml中进行配置来发挥作用。
5.1.1 拦截器工作原理拦截器围绕着Action和Result的执行而执行,如图5-1-1所示。Action被一系列的拦截器包裹,首先执行Action之前的拦截器,并按照顺序依次执行拦截器1、拦截器2、拦截器3……,在Action和Result执行过之后,拦截器会再一次执行,并按照相反的顺序依次执行,图5-1-2清晰的显示了这种顺序。在这一系列执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器的执行。
Struts 2拦截器_conversionError图5.1.1 拦截器工作原理
Struts 2拦截器_自定义拦截器_02图5.1.2 Struts 2拦截器时序图
5.1.2 Struts 2自带拦截器Struts 2框架提供了一系列功能强大的拦截器,它们实现了框架的大部分功能,同时在实际开发中我们也可以灵活应用这些Struts 2自带的拦截器。打开Struts 2源文件中的struts-default.xml文件,如图5.1.3所示,Struts 2自带的拦截器就配置在这个文件里。
Struts 2拦截器_servletConfig_03图5.1.3 Struts 2自带拦截器
单个拦截器由
下面对Struts 2自带的拦截器进行简单介绍:
Ø checkbox:添加了对表单中checkbox自动处理的代码,将没有选中的checkbox的内容
设定为false,而HTML默认情况下不提交没有选中的checkbox。
conversionError:将错误信息从ActionContext中添加到Action的属性字段中。
createSession:自动创建HttpSession,用来为需要使用到HttpSession的拦截器服务。
execAndWait:在后台执行Action,同时将用户带到一个中间的等待页面。
exception:捕获异常并能根据异常类型映射到用户自定义的错误页面。
fileUpload:提供文件上传功能。
params:将请求中的参数设置到Action的属性上。
scope:将Action状态存入session和application的简单方法。
servletConfig:提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方
式访问。
token:防止表单重复提交。
tokenSession:和token一样,不过双击的时候把请求的数据存储在session中。
validation:执行数据校验。
workflow:调用Action的validate方法,一旦有错误返回就终止执行流程。
上面列出了Struts 2常用的拦截器,在实际应用中,我们经常需要组合不同的拦截器形成一个拦截器栈,Struts 2框架在struts-default.xml中定义了一个默认的拦截器栈defaultStack,如图5.1.4所示,这个拦截器栈组合了多个拦截器,并且这些拦截器的顺序都是经过精心设计的,能满足大多数Web应用的需求。在struts.xml中,我们自定义的包(package)通常都要继承struts-default包,而此包指定了defaultStack拦截器栈为默认拦截器栈,所以如果用户的自定义包继承了struts-default包,也会自动将defaultStack做为默认拦截器。如果用户没有为Action指定拦截器,系统将会自动把defaultStack拦截器栈作用于此Action。
Struts 2拦截器_自定义拦截器_04图5.1.4 defaultStack拦截器栈
5.2 配置拦截器拦截器的使用分为三个步骤:
(1) 实现拦截器类
(2) 在struts.xml中定义拦截器或拦截器栈
(3) 为Action配置拦截器或拦截器栈
如果我们使用的是Struts 2自带的拦截器,那么只需要进行第三步即可;如果我们使用的是自己开发的拦截器,就需要进行以上三步。下面是配置语法。
代码语言:javascript复制
... ...
... ...
所有的拦截器或拦截器栈都定义在
拦截器栈由
定义好拦截器或拦截器栈以后,需要在Action的配置中为
5.3 自定义拦截器5.3.1 如何使用自定义的拦截器虽然Struts 2提过了如此丰富的拦截器,但是在实际应用中,我们仍需要自己开发拦截器以满足经常变化的业务需求。
自定义的拦截器类通常需要实现com.opensymphony.xwork2.interceptor.lnterceptor 接口,该接口的源代码如下所示。
代码语言:javascript复制public interface Interceptor {
void destroy();
void init();
String intercept (ActionInvocation invocation) throws Exception;
}
}该接口定义了三个方法:
init(),该方法执行于拦截器执行拦截之前,且每个拦截器只执行一次。因此,该方法的
主要用于打开某些资源。
destroy(),该方法与init()方法对应。在拦截器实例被销毁之前,系统将回调此方法,销
毁在init()方法中打开的资源。
intercept(Actionlnvocationinvocation),该方法是用户需要实现的拦截器动作,返回一个result配置字符串作为逻辑视图。该方法的ActionInvocation参数包含被拦截的Action的引用,可以通过调用该参数的invoke方法,将控制权转给下一个拦截器或者Action。详见表7-1-1所示。
表7-1-1 Actionlnvocation类的常用方法
方法
描述
Object getAction()
获得与拦截器关联的Action,注意进行强制类型转换。
String invoke()throws Exception
继续执行后面的拦截器或Action,可能抛出任何异常。
除此之外,Struts2还提供了一个com.opensymphony.xwork2.interceptor.Abstractlnterceptor类,该类提供了一个init方法和destroy方法的空实现。如果自定义的拦截器不需要申请资源,就无须实现这两个方法。所以,继承自Abstractlnterccptor类来实现自定义拦截器会更加简便。
示例5.1
考虑一般的WEB应用,基本都可分为前台和后台两部分,后台主要是对整个WEB应用进行管理,所以要使用后台必须先登录,后台部分可能包含了很多的Action和JSP视图,我们必须保证用户不能直接访问后台的每一个Action和JSP视图,或者说要想访问就必须先登录,这属于访问控制,这种情况非常适合使用拦截器来解决,接下来我们使用拦截器重构登录案例,把登录验证用拦截器来实现。
(1) 实现拦截器类
代码语言:javascript复制public class LoginInterceptor implements Interceptor {
public void destroy() {
}
public void init() {
}
public String intercept(ActionInvocation ai) throws Exception {
HttpSession session = ServletActionContext.getRequest().getSession();
User user = (User)session.getAttribute("loginUser");
if(user!=null)
return ai.invoke(); //登录成功则继续执行后面的拦截器或Action
else
return "error";
}
}
(2) 实现Action。
public class LoginAction extends ActionSupport{
private String name;
private String pwd;
//省略getter和setter方法
public String execute()
{
return SUCCESS;
}
}由于我们把登录业务放在了拦截器中实现,所以Action中就无需编写业务实现代码了,直接在execute方法中返回了SUCCESS。
(3) 登录视图页面login.jsp
代码语言:javascript复制
(4) 在struts.xml配置文件中配置LoginAction的拦截器。
代码语言:javascript复制
在上述代码中,我们首先使用
如果其他的Action也需要进行登录访问控制,就只需要为该Action配置实现登录验证的拦截器即可。
5.3.2 默认拦截器通常情况下,WEB应用的后台部分可能包含了很多的Action和JSP视图,为了实现访问控制,我们要给后台的每个Action都配置拦截器,虽然能够实现,但是过于繁琐,更好的解决方案就是给这些后台Action配置一个默认的拦截器(栈)。
默认拦截器(栈)定义在包(package)中,该包(package)中的所有Action都共享使用该默认拦截器(栈),每个包(package)中只能定义一个默认拦截器(栈)。
在struts.xml文件中使用
代码语言:javascript复制