struts2 ModelDriven 和 Preparable 拦截器
Struts2 运行流程图-1
ActionProxy 是 Action 的一个代理类,也就是说Action的调用是通过 ActionProxy 实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法.
ActionInvocation就是Action的调用者。ActionInvocation在Action的执行过程中,负责Interceptor、Action和Result等一系列元素的调度。
默认的拦截器栈
Params 拦截器
Parameters 拦截器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中. 如果某个字段在模型里没有匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对象
把 Action 和 Model 隔开
在使用 Struts 作为前端的企业级应用程序时把 Action 和 Model 清晰地隔离开是有必要的: 有些 Action 类不代表任何Model 对象, 它们的功能仅限于提供显示服务
如果 Action 类实现了 ModelDriven 接口,该拦截器将把 ModelDriven 接口的 getModel() 方法返回的对象置于栈顶
ModelDriven 拦截器
Action 实现 ModelDriven 接口后的运行流程
1). 先会执行 ModelDrivenInterceptor 的 intercept 方法.
1 public String intercept(ActionInvocation invocation) throws Exception { 2 //获取 Action 对象: EmployeeAction 对象, 此时该 Action 已经实现了 ModelDriven 接口 3 //public class EmployeeAction implements RequestAware, ModelDriven<Employee> 4 Object action = invocation.getAction(); 5 6 //判断 action 是否是 ModelDriven 的实例 7 if (action instanceof ModelDriven) { 8 //强制转换为 ModelDriven 类型 9 ModelDriven modelDriven = (ModelDriven) action; 10 //获取值栈 11 ValueStack stack = invocation.getStack(); 12 //调用 ModelDriven 接口的 getModel() 方法 13 //即调用 EmployeeAction 的 getModel() 方法 14 /* 15 public Employee getModel() { 16 employee = new Employee(); 17 return employee; 18 } 19 */ 20 Object model = modelDriven.getModel(); 21 if (model != null) { 22 //把 getModel() 方法的返回值压入到值栈的栈顶. 实际压入的是 EmployeeAction 的 employee 成员变量 23 stack.push(model); 24 } 25 if (refreshModelBeforeResult) { 26 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); 27 } 28 } 29 return invocation.invoke(); 30 }
View Code
2). 执行 ParametersInterceptor 的 intercept 方法: 把请求参数的值赋给栈顶对象对应的属性. 若栈顶对象没有对应的属性, 则查询值栈中下一个对象对应的属性...
3). 注意: getModel 方法不能提供以下实现. 的确会返回一个 Employee 对象到值栈的栈顶. 但当前 Action 的 employee 成员变量却是 null.
public Employee getModel() {return new Employee();
}
Preparable 拦截器
Struts 2.0 中的 modelDriven 拦截器负责把 Action 类以外的一个对象压入到值栈栈顶, 而 prepare 拦截器负责准备为 getModel() 方法准备 model
PrepareInterceptor拦截器用方法
若 Action 实现 Preparable 接口,则 Action 方法需实现 prepare() 方法
PrepareInterceptor 拦截器将调用 prepare() 方法,prepareActionMethodName()方法 或 prepareDoActionMethodName ()方法
PrepareInterceptor 拦截器根据 firstCallPrepareDo 属性决定获取 prepareActionMethodName 、prepareDoActionMethodName的顺序。默认情况下先获取 prepareActionMethodName (), 如果没有该方法,就寻找prepareDoActionMethodName()。如果找到对应的方法就调用该方法
PrepareInterceptor 拦截器会根据 alwaysInvokePrepare 属性决定是否执行prepare()方法
使用 paramsPrepareParamsStack 拦截器栈
Struts 2.0的设计上要求 modelDriven 在 params 之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在 prepare之前运行params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。
使用 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 操作而言:
I. 先为 EmployeeAction 的 employeeId 赋值
II. 根据 employeeId 从数据库中加载对应的对象, 并放入到值栈的栈顶
III. 再为栈顶对象的 employeeId 赋值(实际上此时 employeeId 属性值已经存在)
IV. 把栈顶对象的属性回显在表单中.
流程如下:
4). 关于回显: Struts2 表单标签会从值栈中获取对应的属性值进行回显.
使用 PrepareInterceptor 和 Preparable 接口.
关于 PrepareInterceptor [分析后得到的结论]
若 Action 实现了 Preparable 接口, 则 Struts 将尝试执行 prepare[ActionMethodName] 方法,
若 prepare[ActionMethodName] 不存在, 则将尝试执行 prepareDo[ActionMethodName] 方法. 若都不存在, 就都不执行.
若 PrepareInterceptor 的 alwaysInvokePrepare 属性为 false, 则 Struts2 将不会调用实现了 Preparable 接口的 Action 的 prepare() 方法
可以为每一个 ActionMethod 准备 prepare[ActionMethdName] 方法, 而抛弃掉原来的 prepare() 方法, 将 PrepareInterceptor 的 alwaysInvokePrepare 属性置为 false, 以避免 Struts2 框架再调用 prepare() 方法.
如何在配置文件中为拦截器栈的属性赋值: 参看 /struts-2.3.15.3/docs/WW/docs/interceptors.html.
例子:
<!-- 配置使用 paramsPrepareParamsStack 作为默认的拦截器栈 --><!-- 修改 PrepareInterceptor 拦截器的 alwaysInvokePrepare 属性值为 false --><interceptors><interceptor-stack name="atguigustack"><interceptor-ref name="paramsPrepareParamsStack"><param name="prepare.alwaysInvokePrepare">false</param></interceptor-ref></interceptor-stack></interceptors><default-interceptor-ref name="atguigustack"/>
源代码解析
1 public String doIntercept(ActionInvocation invocation) throws Exception { 2 //获取 Action 实例 3 Object action = invocation.getAction(); 4 5 //判断 Action 是否实现了 Preparable 接口 6 if (action instanceof Preparable) { 7 try { 8 String[] prefixes; 9 //根据当前拦截器的 firstCallPrepareDo(默认为 false) 属性确定 prefixes 10 if (firstCallPrepareDo) { 11 prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX}; 12 } else { 13 prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX}; 14 } 15 //若为 false, 则 prefixes: prepare, prepareDo 16 //调用前缀方法. 17 PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes); 18 } 19 catch (InvocationTargetException e) { 20 21 Throwable cause = e.getCause(); 22 if (cause instanceof Exception) { 23 throw (Exception) cause; 24 } else if(cause instanceof Error) { 25 throw (Error) cause; 26 } else { 27 throw e; 28 } 29 } 30 31 //根据当前拦截器的 alwaysInvokePrepare(默认是 true) 决定是否调用 Action 的 prepare 方法 32 if (alwaysInvokePrepare) { 33 ((Preparable) action).prepare(); 34 } 35 } 36 37 return invocation.invoke(); 38 }
View Code
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 executemethodName = DEFAULT_INVOCATION_METHODNAME;}//获取前缀方法Method method = getPrefixedMethod(prefixes, methodName, action);//若方法不为 null, 则通过反射调用前缀方法if (method != null) {method.invoke(action, new Object[0]);} }
View Code
PrefixMethodInvocationUtil.getPrefixedMethod 方法:
public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {assert(prefixes != null);//把方法的首字母变为大写String capitalizedMethodName = capitalizeMethodName(methodName);//遍历前缀数组for (String prefixe : prefixes) {//通过拼接的方式, 得到前缀方法名: 第一次 prepareUpdate, 第二次 prepareDoUpdateString prefixedMethodName = prefixe + capitalizedMethodName;try {//利用反射获从 action 中获取对应的方法, 若有直接返回. 并结束循环.return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);}catch (NoSuchMethodException e) {// hmm -- OK, try next prefixif (LOG.isDebugEnabled()) {LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());}}}return null; }
View Code
转载于:https://www.cnblogs.com/linyueshan/p/5686623.html
struts2 ModelDriven 和 Preparable 拦截器相关推荐
- 使用struts2中默认的拦截器以及自定义拦截器
转自:http://blog.sina.com.cn/s/blog_82f01d350101echs.html 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Acti ...
- 【struts2】预定义拦截器
1)预定义拦截器 Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器.由于Struts2的默认拦截器声明和引用都在这个St ...
- struts2模型驱动和令牌拦截器
模型驱动: *要从页面中获取表单元素的值,需要在动作类中声明与页面元素同名的属性.导致动作类中既有javabean又有业务方法. *将javabean和业务方法进行分离: *将重新创建一个javabe ...
- Struts2——(7)拦截器组件
AOP:面向切面编程(通过配置文件来指定作用到目标对象) OOP:面向对象编程 AOP具有很好的可插拔特性,很灵活. 可用于封装共通的业务处理,之后可以通过配置作用到Action组件上. 共通的业务处 ...
- struts2(三) 输入校验和拦截器
前面知道了struts2的架构图和struts2的自动封装表单参数和数据类型自动转换,今天来学struts2的第三第四个东西,输入校验和拦截器, --WH 一.输入校验 在以前我们写一个登录页面时,并 ...
- Struts2 源码分析——拦截器的机制
本章简言 上一章讲到关于action代理类的工作.即是如何去找对应的action配置信息,并执行action类的实例.而这一章笔者将讲到在执行action需要用到的拦截器.为什么要讲拦截器呢?可以这样 ...
- Struts2入门(二)——配置拦截器
一.前言 之前便了解过,Struts 2的核心控制器是一个Filter过滤器,负责拦截所有的用户请求,当用户请求发送过来时,会去检测struts.xml是否存在这个action,如果存在,服务器便会自 ...
- 在struts2中配置自定义拦截器放行多个方法
源码: 自定义的拦截器类: //自定义拦截器类:LoginInterceptor ; package com.java.action.interceptor; import javax.servlet ...
- struts2开发4--自定义拦截器把不文明用语改变成***
struts2拦截器是在访问某个Action或者Action的某个方法.字段之前或者之后实施拦截,并且struts2拦截器是可插拔的,拦截器是AOP的一种实现.这里重点介绍下自定义文字过滤拦截器,把我 ...
最新文章
- 洛谷 P1208混合牛奶【贪心】
- tomcat 外网访问不了_免费云服务器/jdk环境配置/Tomcat简单配置
- Swift - 14 - 字符串的基础操作
- 选择开发语言和学习的路径(这个标题可能有点不准确)
- 使用 Eclipse 建立包的时候,“name”下可选项“Create package-info.java”的作用是什么?
- web.config中namespace的配置(针对页面中引用)
- mysql 取字符串首字母_MySQL通过函数获取字符串汉字拼音首字母大写字符串
- FlexSIM.ED v4.0 1CD(生产排程,虚拟管理,能力平衡软件)
- Windows 相关镜像及补丁下载地址
- Tomcat发布项目时,浏览器地址栏图标的问题
- Arcgis学习视频
- Android studio进行文件,代码对比
- CUGBACM130715 组队赛 BNU Curvy Little Bottles - from lanshui_Yang
- Android之Dex动态加载机制解析
- CSS峰会圆桌论道丨共享产业数字化升级中的安全探索
- P4086 [USACO17DEC]My Cow Ate My Homework S(静态数据预处理:后缀和、后缀最小值)
- 微信小程序:音乐播放器带进度条
- 便携式计算机的基本知识,使用便携式计算机,错误的做法是()A、非涉密便携机不得存储或处理涉密信息B、涉密便携机需经过保 - 普法考试题库问答...
- 公租房租赁合同怎么填
- (三)Horizon 队列管理工具