5.Struts 2拦截器(Interceptor)

Struts 2专栏目录


Struts 2专栏目录(点击进入…)



Struts 2组成部分

Struts 2由两部分组成:①XWork 2、②Struts 2
XWork 2是一个命令模式的框架,是Struts 2的基础;它的核心包括Action、Result、拦截器。Struts 2扩展了这些概念的基础实现,用于支持Web应用程序的开发。


为什么使用拦截器?

任何优秀的MVC框架都会提供一些通用的操作,如请求数据的封装、类型转换、数据校验、解析上传的文件、防止表单的多次提交等。
Struts 2将它的核心功能放到拦截器中实现而不是集中在核心控制器中实现,把大部分控制器需要完成的工作按功能分开定义,每个拦截器完成一个功能,而完成这些功能的拦截器可以自由选择、灵活组合,需要哪些只需要在struts.xml指定即可,从而增加了框架的灵活性,有利于系统解耦。

拦截器的方法在Action执行之前或者执行之后自动的执行,从而将通用的操作动态地插入到了可插拔式。需要哪个就“插入”一个拦截器,不需要某个功能就“拔出”一个拦截器。可以任意地组合Action提供的附加功能,而不需要修改Action代码。

如果有一批拦截器经常固定在一起使用,可以将这些执行小粒度功能的拦截器定义成大粒度的拦截器栈(根据不同应用需求而定义的拦截器组合)。
从结构上看,拦截器栈相当于与多个拦截器的组合
从功能上看,拦截器栈也是拦截器,同样可以和其他拦截器(或拦截器栈)一起组成更大粒度的拦截器栈


拦截器的工作原理

Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

拦截器围挠Action和Result的执行而执行

拦截器的实现原理和Servlet Filter的实现原理差不多,以链式执行,对真正要执行的方法(execute())进行拦截
首先执行Action配置拦截器,在Action和Result执行之后,拦截器在一次执行(与先前调用相反的顺序),在此链式的执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器、Action及Result的执行

当ActionInvocation的invoke()方法被调用时,开始执行Action配置的第一个拦截器,拦截器做出相应处理后会再次调用ActionInvocation的invoke()方法,ActionInvocation对象负责跟踪执行过程的状态,并把控制权交给适合的拦截器。ActionInvocation通过调用拦截器的intercept()方法将控制转交给拦截器
拦截器的执行过程可以看作一个递归的过程,后续拦截器继续执行,直到最后一个拦截器,invoke()方法会执行Action


为什么拦截器的执行看作递归过程

框架通过第一次调用ActionInvocation的invoke()方法开始这一过程,ActionInvocation通过调用拦截器的intercept()方法把控制权转交给为Action配置的第一个拦截器。最重要的是intercept()方法把ActionInvocation实例看作参数,在拦截器的处理过程中,它会调用ActionInvocation对象上的invoke()方法来继续调用后续按揭器。
在这里插入图片描述

拦截器有三个阶段,有条件的执行周期:
(1)做一些Action执行前的预处理。拦截器可以准备、过滤、改变或操作任何可以访问的数据、包括Action
(2)调用ActionInvocation的invoke()方法将控制权转交给后续的拦截器或者返回结果字符串终止执行。如果拦截器决定请求的处理不应该继续,可以不调用invoke()方法,而是直接返回一个控制字符串。通过这种方式,可以停止后续的执行,并且决定将那个结果呈现给客户端
(3)做一些Action执行后的处理。此时拦截器依然可以访问改变可以访问的对象和数据,只是此时框架已经选择了一个结果呈现给客户端了


拦截器的配置

两个步骤
(1)通过<interceptors/>的子元素<interceptor……/>元素来定义拦截器(package下)
(2)通过<interceptor-ref……/>元素来使用拦截器(action下)

在struts.xml文件中,首先在<package>中配置<interceptors/>的子元素<interceptor……/>来定义拦截器,<interceptor>元素的name属性与class属性是必须填写的

属性描述
name指定拦截器的名字,依然使用interceptor-ref元素指定引用的拦截器
class指定拦截器的全限定类名

然后在<action>元素中使用<interceptor-ref>子元素指定引用的拦截器,如果还需要指定默认拦截器,就需要一并添加到<action>中(default-interceptor-ref)

如果想要把多个拦截器组成一个拦截器栈,就需要在interceptors元素中使用interceptor-stack元素定义拦截器栈


Struts 2内置拦截器

1.Params

提供了框架必不可少的功能,将请求中的数据设置到Action的属性上

2.staticParams

将配置文件中通过元素的子元素设置的参数设置到对应的Action的属性中

3.servletConfig

提供了将一种源于Servlet API的各种对象注入Action当中的简洁方法。Action必须实现相对应的接口,servletConfig拦截器才能将对应的Servlet对象注入Action中

接口可以由Action实现,用来取得Servlet API的不同对象

接口作用
ServletContextAware设置ServletContext
ServletRequestAware设置HttpServletReque
ServletResponseAware设置HttpServletResponse
ParameterAware设置Map类型的请求参数
RequestAware设置Map类型的请求(HttpServletRequest)属性
SessionAware设置Map类型的会话(HttpSession)属性
ApplicationAware设置Map类型的应用程序作用域对象(ServletContext)

4.fileUpload

将文件和元数据从多重请求(multipart/form-data)转换为常规的请求数据,以便将它们设置在对应的Action属性上,实现文件上传

5.validation

用于执行数据校验

6.workflow

提供当数据校验错误时终止执行流程的功能

7.Exception

用于捕获异常,并且能够根据异常将捕获的异常映射到用户自定义的错误页面。该拦截器执行时应该位于所定义的所有拦截器中的第一个

Struts 2内置拦截器栈
struts-default.xml中定义了一个非常重要的拦截器栈——defaultStack拦截器栈。defaultStack拦截器栈组合了多个拦截器,这些拦截器,这些拦截器的顺序经过精心的设计,能够满足大多数Web应用程序的需求,只要在定义包的过程中继承struts-default包


自定义拦截器

在Struts 2框架中所有的Struts 2拦截器都直接或间接地实现接口:com.opensymphony.xwork.interceptor.Interceptor

该接口提供了三种方法:

方法描述
void init()该拦截器被初始化之后,在该拦截器执行拦截之前,系统会回调该方法。对于每个拦截器而言,此方法只执行一次
void destroy()该方法跟init()方法对应。在拦截器实例被销毁之前,系统将回调该方法
String interceptor(ActionInvocation invocation) throws Exception该方法是用户需要实现的拦截器动作。该方法会返回一个字符串作为逻辑视图

除此之外,继承com.opensymphony.work2.interceptor.AbstractInterceptor类是更简单的一种实现拦截器的方式,AstractInterceptor类提供了init()和destroy()方法的空实现,这样就只需要实现interceptor()方法,就可以创建自己的拦截器。

在package中如果定义default-interceptor-ref默认拦截器,那么包中的所有Action都会默认调用拦截器。

实现Interceptor接口

(1)void init()

初始化拦截器所需资源

(2)void destroy()

释放在init()中分配的资源

(3)String intercept(ActionInvocation ai) throws Exception

①实现拦截器功能
②利用ActionInvocation参数获取Action状态
③返回结果码(result)字符串


继承AbstractInterceptor类

提供了init()和destroy()方法的空实现,只需要实现intercept方法即可。

(1)编写自定义拦截器,继承自AbstractInterceptor

public class MyTimerInterceptor extends AbstractInterceptor {
	//继承AbstractInterceptor,重写interceptor方法
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("进入拦截器!!!");
		// 预处理工作
		long start = System.currentTimeMillis();
		// 执行后续拦截器或Action
		// 如果后续没有拦截器了,则执行Action返回的结果是Action返回的结果
		//String result = invocation.invoke();
		// 后续处理工作
		long end = System.currentTimeMillis() - start;
		System.out.println("times:" + end);
		return "ok";
	}
}

(2)在配置文件中定义拦截器

<!-- 在package下,定义拦截器 -->
<interceptors>
	<interceptor name="time"
		class="cn.my.interceptor.MyTimerInterceptor">
	</interceptor>
</interceptors>

(3)引用拦截器

<!-- 在Action下 -->
<interceptor-ref name="time"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值