使用 paramsPrepareParamsStack 拦截器栈后的运行流程
2. 使用 paramsPrepareParamsStack 拦截器栈后的运行流程
1). paramsPrepareParamsStack 和 defaultStack 一样都是拦截器栈. 而 struts-default 包默认使用的是defaultStack
2). 可以在 Struts 配置文件中通过以下方式修改使用的默认的拦截器栈
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
3). paramsPrepareParamsStack 拦截器在于
params -> modelDriven -> params
可以先把请求参数赋给 Action 对应的属性, 再根据赋给 Action 的那个属性值决定压到值栈栈顶的对象, 最后再为栈顶对象的属性赋值.
对于 edit 操作而言:
1. 先为 EmployeeAction 的 employeeId 赋值
2. 根据 employeeId 从数据库中加载对应的对象, 并放入到值栈的栈顶
3. 再为栈顶对象的 employeeId 赋值(实际上此时 employeeId 属性值已经存在)
4. 把栈顶对象的属性回显在表单中
5.表单数据被修改后,提交数据,此时所有数据都是放在栈顶对象里
6.所以我们要Modeldriven接口把栈顶对象变成我们的对象
4). 关于回显: Struts2 表单标签会从值栈中获取对应的属性值进行回显.
5). 存在的问题:
getModel 方法
public Employee getModel() {
if(employeeId == null)
employee = new Employee();
else
employee = dao.get(employeeId);
return employee;
}
I. 在执行删除的时候, employeeId 不为 null, 但 getModel 方法却从数据库加载了一个对象. 不该加载!
II. 指向查询全部信息时, 也 new Employee() 对象. 浪费!
6). 解决方案: 使用 PrepareInterceptor 和 Preparable 接口.
7). 关于 PrepareInterceptor---对于这个拦截器,它的作用就是为ModelDriven拦截器做准备,如果调用了prepare[ActionMethodName](), 或者prepare()
----方法则modelDriven的getModel()方法不会被再执行,
[分析后得到的结论]
若 Action 实现了 Preparable 接口, 则 Struts 将尝试执行 prepare[ActionMethodName] 方法,
若 prepare[ActionMethodName] 不存在, 则将尝试执行 prepareDo[ActionMethodName] 方法.
若都不存在, 就都不执行.
若 PrepareInterceptor 的 alwaysInvokePrepare 属性为 false(默认为true),
则 Struts2 将不会调用实现了 Preparable 接口的 Action 的 prepare() 方法
[能解决 5) 的问题的方案]
可以为每一个 ActionMethod 准备 prepare[ActionMethdName] 方法, 而抛弃掉原来的 prepare() 方法
将 PrepareInterceptor 的 alwaysInvokePrepare 属性置为 false, 以避免 Struts2 框架再调用 prepare() 方法.
如何在配置文件中为拦截器栈的属性赋值: 参看 /struts-2.3.15.3/docs/WW/docs/interceptors.html
<interceptors>
<interceptor-stack name="parentStack">
<interceptor-ref name="defaultStack">
<param name="params.excludeParams">token</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="parentStack"/>
----------------------------------源代码解析---------------------------------
public String doIntercept(ActionInvocation invocation) throws Exception {
//获取 Action 实例
Object action = invocation.getAction();
//判断 Action 是否实现了 Preparable 接口
if (action instanceof Preparable) {
try {
String[] prefixes;
//根据当前拦截器的 firstCallPrepareDo(默认为 false) 属性确定 prefixes
if (firstCallPrepareDo) {
prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
} else {
prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
}
//若为 false, 则 prefixes: prepare, prepareDo
//调用前缀方法.
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
}
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
} else if(cause instanceof Error) {
throw (Error) cause;
} else {
throw e;
}
}
//根据当前拦截器的 alwaysInvokePrepare(默认是 true) 决定是否调用 Action 的 prepare 方法
if (alwaysInvokePrepare) {
((Preparable) action).prepare();
}
}
return invocation.invoke();
}
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes) 方法:
public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
//获取 Action 实例
Object action = actionInvocation.getAction();
//获取要调用的 Action 方法的名字(update)
String methodName = actionInvocation.getProxy().getMethod();
if (methodName == null) {
// if null returns (possible according to the docs), use the default execute
methodName = DEFAULT_INVOCATION_METHODNAME;
}
//获取前缀方法
Method method = getPrefixedMethod(prefixes, methodName, action);
//若方法不为 null, 则通过反射调用前缀方法
if (method != null) {
method.invoke(action, new Object[0]);
}
}
PrefixMethodInvocationUtil.getPrefixedMethod 方法:
public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
assert(prefixes != null);
//把方法的首字母变为大写
String capitalizedMethodName = capitalizeMethodName(methodName);
//遍历前缀数组
for (String prefixe : prefixes) {
//通过拼接的方式, 得到前缀方法名: 第一次 prepareUpdate, 第二次 prepareDoUpdate
String prefixedMethodName = prefixe + capitalizedMethodName;
try {
//利用反射获从 action 中获取对应的方法, 若有直接返回. 并结束循环.
return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
}
catch (NoSuchMethodException e) {
// hmm -- OK, try next prefix
if (LOG.isDebugEnabled()) {
LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
}
}
}
return null;
}
使用 paramsPrepareParamsStack 拦截器栈后的运行流程的更多相关文章
- [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- 【Java EE 学习 69 上】【struts2】【paramsPrepareParamsStack拦截器栈解决model对象和属性赋值冲突问题】
昨天有同学问我问题,他告诉我他的Action中的一个属性明明提供了get/set方法,但是在方法中却获取不到表单中传递过来的值.代码如下(简化后的代码) public class UserAction ...
- 从源代码分析modelDriven拦截器和params拦截器和拦截器prepare 和paramsPrepareParamsStack拦截器栈(让你的Struts2代码更简洁——如何培养框架设计能力
源代码文件:Web App Libraries/struts2-core-2.3.15.3.jar/struts-default.xml 拦截器modelDriven: <interceptor ...
- Struts(十七):通过CURD来学习paramsPrepareParams拦截器栈
背景: 通过上一章节<Struts(十六):通过CURD来学习Struts流程及ModelDriven的用法>学习了ModelDriven拦截器的用法,上章节中讲到了edit功能. 要修改 ...
- struts2 paramsPrepareParamsStack拦截器简化代码(源码分析)
目录 一.在讲 paramsPrepareParamsStack 之前,先看一个增删改查的例子. 1. Dao.java准备数据和提供增删改查 2. Employee.java 为model 3. E ...
- Struts2默认拦截器栈及内建拦截器使用具体解释
Struts2内建拦截器介绍: alias (别名拦截器):同意參数在跨越多个请求时使用不同别名,该拦截器可将多个Action採用不同名字链接起来,然后用于处理同一信息. autowiring ...
- 第十篇——Struts2的拦截器栈
拦截器栈: 从结构上看:拦截器栈相当于多个拦截器的组合: 从功能上看:拦截器栈也是拦截器. 默认拦截器栈: 在struts-core.jar包中的struts-default.xml中自定义了一个de ...
- SpringMVC学习 十三 拦截器栈
拦截器栈:就是有多个拦截器同时拦截相同的控制器(controller)请求,这写拦截器就构成了拦截器栈. 栈的特点是先进后出,在拦截器栈中也是如此,如果先执行了preHandle方法,也就是意味着先进 ...
- Struts2学习之拦截器栈
© 版权声明:本文为博主原创文章,转载请注明出处 拦截器栈: - 从结构上看:拦截器栈相当于多个拦截器的组合 - 从功能上看:拦截器栈也是拦截器 默认拦截器栈: - 在struts-core.jar中 ...
随机推荐
- c语言打印一个整数的二进制形式
printf函数没有这个功能,如果想打印一个数的二进制形式,就得自己计算.下面是我看到的最简便的算法: #include <stdio.h> int main(int argc, char ...
- atitit..主流 浏览器 js 引擎 内核 市场份额 attialx总结vOa9
atitit..主流 浏览器 js 引擎 内核 市场份额 attialx总结vOa9 1. 浏览器内核 1 2. 浏览器的主要组件包括: 2 2.1. 主要组件体系结构 2 2.2. WebCore ...
- Oracle 11g安装图文攻略
一.Oracle 下载 注意Oracle分成两个文件,下载完后,将两个文件解压到同一目录下即可. 路径名称中,最好不要出现中文,也不要出现空格等不规则字符. 官方下地址: http://www.ora ...
- C++-教程1-VS2010环境设置
一.需要下载的软件 1.visual studio 2010\\xxzx\tools\编程工具\MICROSOFT\VISUAL.STUDIO\VISUAL.STUDIO.201032位cn_visu ...
- python学习笔记(5)--泡菜:永久存储
说明: 1. 导入pickle泡菜模块. 2. wb方式(二进制)创建.pkl文件. 3. pickle.dump把一个数组或什么数据灌进这个新建的文件. 4. 然后就生成了一个pkl文件,用来存放数 ...
- session退出页面
简单的session退出页面,jsp: <%@ page language="java" contentType="text/html; charset=utf-8 ...
- lockf函数的使用
#include<stdio.h> #include<unistd.h> void main() {int p1,p2,i; while((p1=fork())==-1);// ...
- inline-block元素的空白间距解决方法<转>
使用inline-block来代替float进行布局,或者使用inline-block来实现元素的居中效果.有关于使用inline-block来代替float的讨论也蛮多的. 不过就是使用inline ...
- Android——手机尺寸相关的概念 +尺寸单位+关于颜色
手机的尺寸: 屏幕对角线的长度,单位为英寸(2.54cm) 手机的分辨率: 屏幕能显示的像素的数量, 一般用在长方向上数量*宽方向上数量来表达 手机的像素密度: pixels per inch,也称P ...
- JVM系统性能监控总结
(1) uptime 查看系统运行时间.连接数(终端连接数).平均负载 (2) top 查看CPU.内存.交换空间使用情况,可以看到当前系统性能进程消耗资源情况 (3) vmstat 统计系统CPU. ...