struts2 拦截器和actioninvocation、PreResultListener
Interceptor说明
Interceptor的接口定义没有什么特别的地方,除了init和destory方法以外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的Action调度者。
我在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义(详细看DefaultActionInvocation源代码):
1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
2. 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。
3.

DefaultActionInvocation部分源代码:
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
UtilTimerStack.profile("interceptor: "+interceptor.getName(),
new UtilTimerStack.ProfilingBlock<String>() {
public String doProfiling() throws Exception {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);//递归调用拦截器
return null;
}
});
} else {
resultCode = invokeActionOnly();
}
每个拦截器中的代码的执行顺序,在Action之前,拦截器的执行顺序与堆栈中定义的一致;而在Action和Result之后,拦截器的执行顺序与堆栈中定义的顺序相反。
Interceptor拦截类型
从上面的分析,我们知道,整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上,我们也正式根据这句代码的调用位置,来进行拦截类型的区分的。在Struts2中,Interceptor的拦截类型,分成以下三类:
1. before
before拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之前。这些代码,将依照拦截器定义的顺序,顺序执行。
2. after
after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之后。这些代码,将一招拦截器定义的顺序,逆序执行。
PreResultListener
有的时候,before拦截和after拦截对我们来说是不够的,因为我们需要在Action执行完之后,但是还没有回到视图层之前,做一些事情。Struts2同样支持这样的拦截,这种拦截方式,是通过在拦截器中注册一个PreResultListener的接口来实现的。
如:在拦截器中使用如下代码,其中MyPreResultListener实现了PreResultListener 接口并在beforeResult方法中做了一些事情然后在拦截器类中加入action.addPreResultListener(new MyPreResultListener());
从源码中,我们可以看到,我们之前提到的Struts2的Action层的4个不同的层次,在这个方法中都有体现,他们分别是:拦截器(Interceptor)、Action、PreResultListener和Result。在这个方法中,保证了这些层次的有序调用和执行
问题
使用Struts2作为web框架,知道它的拦截器(Interceptor)机制,类似与Filter和spring的AOP,于是实现了一个为Action增加自定义前置(before)动作和后置动作(after)的拦截器(曰:WInterceptor),不过用一段时间发现,在WInterceptor的after中,对Action对象的属性修改在页面看不到,对请求对象的属性设置也无效。为什么在调用了Action之后(invokeAction())之后,request就不能使用了呢,拦截器不能改变Action的Result么?
问题的关键在于,在调用actionInvocation.invoke()的之后,不仅执行类Action,也执行类Result。因而,等退回到拦截器的调用代码时,Result已经生成,View已经确定,这时你再修改模型(Action的属性)或请求对象的属性,对视图不会有任何影响。
解决办法:
方法一:使用现成的PreResultListener监听器事件
搞清楚原因,卷起袖子干吧,只要让WInterpretor的after事件,放在Result的生成之前就行了。
看看XWork的拦截器接口注入的actionInvocation,其实就提供增加Result执行的前置监听事件-PreResultListener:
- void addPreResultListener(PreResultListener listener);
void addPreResultListener(PreResultListener listener);
因此,让拦截器实现这个接口,就可以自然实现Action执行after事件了。
方法二,实现自己的 ActionInvocation ,手动分离Action和Result的执行
本来前面的方法已经很好了,可是,可是啊,在addPreResultListener里的异常,不会被Struts的框架捕获,而且,addPreResultListener接口不能传递自己的上下文参数,难道动用ThreadLocal传参?
研究了一下XWork的ActionInvocation 接口默认实现类DefaultActionInvocation, 写了一个包装类,将Action的执行和Result的生成完全分开,或许有人用的着,放上来,见附件(ActionInvocationWrapper),如有不妥之处请告知。
exeucteAction是执行Action,executeResult是执行Result
struts2 拦截器和actioninvocation、PreResultListener的更多相关文章
- Struts2拦截器原理以及实例
一.Struts2拦截器定义 1. Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现. 2. ...
- 转载 - Struts2 拦截器详细配置过程
出处:http://www.blogjava.net/zzzlyr/archive/2009/10/12/297998.html Struts2 拦截器详细配置过程 1:所有拦截器的超级接口Inter ...
- 深入分析JavaWeb Item47 -- Struts2拦截器与文件上传下载
一.struts2中的拦截器(框架功能核心) 1.过滤器VS拦截器 过滤器VS拦截器功能是一回事. 过滤器是Servlet规范中的技术,能够对请求和响应进行过滤. 拦截器是Struts2框架中的技术. ...
- Struts2 拦截器配置以及实现
@(Java ThirdParty)[Struts|Interceptor] Struts2 拦截器配置以及实现 Struts2的拦截器应用于Action,可以在执行Action的方法之前,之后或者两 ...
- Struts2拦截器的使用 (详解)
Struts2拦截器的使用 (详解) 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Action里面必须最后一定要引用struts2自带的拦截器缺省堆栈default ...
- struts2拦截器
一.自定义拦截器 struts2拦截器类似于servlet过滤器 首先定义一个拦截器这个拦截器实现了Interceptor接口: package cn.orlion.interceptor; impo ...
- Struts2拦截器初涉
Struts2拦截器初涉 正在练习struts,本例是从一个pdf上摘抄的例子,那本pdf都不知道叫什么名字,不过感觉很适合初学者. 在这里要实现一个简单的拦截器"GreetingInter ...
- 浅谈Struts2拦截器的原理与实现
拦截器与过滤器 拦截器是对调用的Action起作用,它提供了一种机制可以使开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了 ...
- struts2—拦截器
在Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack; 一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行 拦截器配置举例(stru ...
随机推荐
- Fiddler捕获 iPhone/Android 流量
由于 Fiddler 作为代理的形式来捕获流量,因此理论上来说是不区分客户端的(当然 Fiddler 要安装在 Windows,毕竟是 .NET 开发的工具). 这一篇文章教你如何利用 Fiddler ...
- C#的输入输出,类型,运算符,语句的练习
//请输入您的姓名.年龄.工作单位, //拼接成一句完整的话 //我叫***,今年**岁了,在****工作. Console.Write("请输入你的姓名:"); string n ...
- Win7怎么用IIS发布网站系统 部署项目
确保系统上已经安装IIS,如果没有安装 请到[控制面板]→[程序]→[程序和功能]→[打开或关闭Windows功能] 选中Internet 信息服务下面的所有选项,确定 获得发布好的程序文件 ...
- 【LintCode】链表求和
问题分析: 我们通过遍历两个链表拿到每个位的值,两个值加上前一位进位值(0或者1)模10就是该位的值,除以10就是向高位的进位值(0或者1). 由于两个链表可以不一样长,所以要及时判断,一旦为null ...
- eclipse/myeclipse下简单更改tomcat的启动等待时间
1.双击server 2.更改timeout
- Django入门之自定义页面
1.创建项目,创建app django-admin.py startproject HelloWord python3 manage.py startapp sync_one #第二步需要进入Hell ...
- BZOJ 4325: NOIP2015 斗地主
4325: NOIP2015 斗地主 Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 684 Solved: 456[Submit][Status] ...
- 【BZOJ-1962】模型王子 DP 猜数问题
1962: 模型王子 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 116 Solved: 66[Submit][Status][Discuss] D ...
- 【bzoj1014】 JSOI2008—火星人prefix
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 (题目链接) 题意 给出一个字符串,要求维护这些操作:询问后缀x与后缀y的LCQ(最长公共前缀 ...
- WHMCS系统API调用
WHMCS:域名管理系统,现在网络上很多借助此系统Shadowsocks插件+ShadowsocksR多用户服务端进行VPN的售卖,能做到流量控制等. 在对接此系统的API时,我发现了很多功能都已经实 ...