当前位置: 首页 > 图文教程 > Java技术 > Web框架 > Web框架:浅谈Struts2中拦截器应用
Struts2简介
java的Struts2中提供了很多新特性,比如智能的默认设置、annotation的使用以及“惯例重于配置”原则的应用,而这一切都大大减少了XML配置。Struts2中的Action都是POJO,这一方面增强了Action本身的可测试性,另一方面也减小了框架内部的耦合度,而HTML表单中的输入项都被转换成了恰当的类型以供action使用。开发人员还可以通过拦截器(可以自定义拦截器或者使用Struts2提供的拦截器)来对请求进行预处理和后处理,这样一来,处理请求就变得更加模块化,从而进一步减小耦合度。模块化是一个通用的主题——可以通过插件机制来对框架进行扩展;开发人员可以使用自定义的实现来替换掉框架的关键类,从而获得框架本身所不具备的功能;可以用标签来渲染多种主题(包括自定义的主题);Action执行完毕以后,可以有多种结果类型——包括渲染JSP页面,Velocity和Freemarker模板,但并不仅限于这些。最后,依赖注入也成了Struts2王国中的一等公民,这项功能是通过Spring框架的插件和Plexus共同提供的,与PicoContainer的结合工作还正在进行中。
Struts2价值
今天,摆在开发人员面前的是众多的java Web开发框架。它们有些来自于开源社区,有些来自于商业公司,还有些是由某些团队内部开发的,以满足当前Web开发所需。目前大约一共有超过40个开源框架,这个数目看上去挺大,但也许还有同样多(如果不是大大多于这个数量的话)的内部构建的框架部署在产品环境中。
既然我们有这么多选择,那为什么要选择Struts2呢?下面列出的这些特性,可能会促使你把Struts2作为你的选择:
? 基于Action的框架
? 拥有由积极活跃的开发人员与用户组成的成熟社区
? Annotation和XML配置选项
? 基于POJO并易于测试的Action
? 与Spring,SiteMesh 和Tiles的集成
? 与OGNL表达式语言的集成
? 基于主题的标签库与Ajax标签
? 多种视图选项 (JSP,Freemarker,Velocity和XSLT)
? 使用插件来扩展或修改框架特性。
在选择一个框架的时候,框架风格的选择是最具有争议性的。
Struts2拦截器
Struts2中提供的很多特性都是通过拦截器实现的,例如异常处理,文件上传,生命周期回调与验证。拦截器从概念上来讲和Servlet过滤器或者JDK 的Proxy类是一样的。它提供了一种对
Action进行预处理和事后处理的功能。和Servlet 过滤器一样,拦截器可以被分层和排序。它还可以访问所执行的Action和所有的环境变量与执行属性。
让我们从依赖注入来开始对拦截器的介绍。正如我们已经看到的一样,依赖注入可以多种不同的实现方式。下面就是对应于不同实现方式的拦截器:
♦ Spring 框架——ActionAutowiringInterceptor拦截器
♦ 请求字符串和表单值—— ParametersInterceptor拦截器
♦ 基于Servlet的对象——ServletConfigInterceptor拦截器
前两种拦截器可以独立工作,不需要Action的帮助,但是最后一种不同,它是在以下几种接口的辅助下工作的:
♦ SessionAware ——通过Map来提供对所有session属性的访问
♦ ServletRequestAware——提供对HttpServletRequest对象的访问
♦ RequestAware ——通过Map来提供对所有request属性的访问
♦ ApplicationAware ——通过Map来提供对所有applicatin属性的访问
♦ ServletResponseAware ——提供对HttpServletResponse对象的访问
♦ ParameterAware ——通过Map来提供对所有request string和表单数据的访问
♦ PrincipalAware ——提供对PrincipleProxy对象的访问;该对象实现了HttpServletRequest对象的有关principle 和role的方法,但是它提供了一个Proxy,因此所有的实现都是独立于Action的。
♦ ServletContextAware ——提供对ServletContext对象的访问
如果要把数据注入到Action中去,那么对应的数据就需要实现必需的接口。
配置
如果要在Action中激活依赖注入功能(或其他任何由拦截器提供的功能),就必须要对Action进行配置。和其他元素一样,许多
拦截器都已经提供了默认的配置项。你只需要确认一下Action所在的Package继承了“struts-default”package。
在配置一个新的拦截器之前,首先要对它进行定义。<interceptors … />和<interceptor … />标签都要直接放到<package>标签里面。像我们上面提到的那些拦截器,它们的配置项就是这样的:
<interceptors>
…
<interceptor name="autowiring"
class="…xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
</interceptors>
我们同时还要确保Action中应用了所需的拦截器。这可以通过两种方式来实现。第一种是把拦截器独立的分配给每一个Action:
<action name="my" class="com.fdar.infoq.MyAction" >
<result>view.jsp</result>
<interceptor-ref name="autowiring"/>
</action>
在这种情况下,Action所应用的拦截器是没有数量限制的。但是拦截器的配置顺序必须要和执行的顺序一样。
第二种方式是在当前的Package下面配置一个默认的拦截器:
<default-interceptor-ref name="autowiring"/>
这个声明也是直接放在<package … /> 标签里面,但是只能有一个拦截器被配置为默认值。
现在拦截器已经被配置好了,每一次Action所映射的URL接到请求时,这个拦截器就会被执行。但是这个功能还是很有限的,因为在大多数情况下,一个Action都要对应有多个拦截器。实际上,由于Struts2的很多功能都是基于拦截器完成的,所以一个Action对应有7、8个拦截器也并不稀奇。可以想象的到,如果要为每一个Action都逐一配置各个拦截器的话,那么我们很快就会变得焦头烂额。因此一般我们都用拦截器栈(interceptor stack)来管理拦截器。下面是struts-default.xml文件中的一个例子:
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
这个配置节点是放在<package … /> 节点中的。每一个 <interceptor-ref … />标签都引用了在此之前配置的拦截器或者是拦截器栈。
我们已经看到了如何在Action中应用拦截器,而拦截器栈的用法也是一模一样的,而且还是同一个标签:
<action name="my" class="com.java.infoq.MyAction" >
<result>view.jsp</result>
<interceptor-ref name="basicStack"/>
</action>
默认拦截器的情况也是一样的——只需要把单个拦截器的名字换成拦截器栈的名字就可以了。
<default-interceptor-ref name="basicStack"/>
由上面的种种情况可以得出,当配置初始的拦截器与拦截器栈时,必须要确保它们的名字是唯一的。
实现拦截器
在应用程序中使用自定义的拦截器是一种优雅的提供跨应用特性的方式。我们只需要实现XWork框架中一个简单的接口,它只有三个方法:
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
如果我们不需要执行其他初始化或清理动作的话,还可以直接继承AbstractInterceptor。这个类对“destroy”和“init”方法进行了重写,但在方法中没有执行任何操作。
ActionInvocation 对象可以用来访问运行时环境,以及Action本身;上下文(包括了Web应用的请求参数,session参数,用户Local等等);Action的执行结果;还有那些调用Action的方法并判断Action是否已被调用。
在上面我们知道了配置拦截器和配置拦截器栈的方式是相同的,如果你需要创建自己的拦截器的话,那么也应当考虑一下创建自定义的拦截器栈。这样才能确保新的拦截器在应用的时候可以贯穿所有需要该拦截器的Action。
评论 (0) All