Struts2拦截器之ModelDrivenInterceptor
叙述套路:
1.这是个啥东西,它是干嘛用的?
2.我知道它能干啥了,那它咋个用呢?
3.它能跑起来了,但是它是咋跑起来的是啥原理呢?
一、ModelDriven是个啥?他能做什么?
从前端页面到后端的参数传递可以分为属性驱动和对象驱动(我瞎编的词(*^__^*) ),属性驱动的意思就是参数从前端传递到后台之后仍然还是参数,需要我们自己按需组装成对象,对象驱动的意思就是参数从前端传递后台之后就自动被组装为了一个对象,ModelDriven实现的就是对象驱动(专业的说法叫模型驱动,但是这个词一看就很不好懂的样子),它做的事情很简单就是在参数拦截器设置参数之前将一个特定的对象放到值栈的栈顶。因为值栈元素有暴露栈中对象属性的特性,所以我们在前端页面中就可以直接访问这个对象的属性而不是还要用对象名导航了,比如user.name可以直接使用name访问。
二、ModelDriven的使用
使用ModelDriven很简单,只要action实现了一个ModelDriven接口即可,这个接口的代码如下:
package com.opensymphony.xwork2; /**
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
* in addition to the Action itself, allowing a FormBean type approach like Struts.
*
* @author Jason Carreira
*/
public interface ModelDriven<T> { /**
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
*
* @return the model
*/
T getModel(); }
这种类似的接口由很多,它们的作用大致如下:
1.类型标识,在别的地方可以使用instanceof来判断一个实例是否实现了某一个接口,这个时候接口起到类型标识的作用。
2.统一动作,使得某一类action可以有统一的动作,比如ModelDriven都可以返回一个对象,Validateable都可以验证数据等等。
需要注意的是ModelDriven是一个泛型接口,所以我们还是尽量在实现的时候就指定类型比较好。
回到正题,来看一个实现了ModelDriven的action:
public class LoginAction extends ActionSupport implements ModelDriven<User> { private User user; public String login() { return SUCCESS;
} @Override
public User getModel() {
if(user==null) user=new User();
return user;
}
public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} }
这个时候在前端页面上就可以直接访问user的username,passwd等等,比如:
<form action="loginAction" method="post">
用户名:<input type="text" name="username" /><br/>
密 码:<input type="password" name="passwd" /><br/>
<input type="submit" value="登录" />
</form>
后台接收到的就是完整的User对象,这只是参数接收的一种方式。
ModelDriven注意事项:执行结果前刷新
如果在execute()等映射到的方法中改变了成员属性user的引用的话,就需要在执行结果前刷新,比如:
public String login() { user=userService.login(user); return SUCCESS;
}
登录的功能是根据username和passwd查询一个新的对象,如果为null说明登录失败,否则返回一个user对象里面装满了此用户的各种信息,但是不论如何,成员属性user的引用已经被修改,想一下当这个方法执行完的时候Action中的成员属性user指向的是一个引用,而ValueStack中的对象user指向的是另一个引用,而我们想要的是等下访问栈顶元素就可以访问到刚刚在login()中查出的那个对象呢,很明显,这个结果是做不到这一点的,那么该怎么办呢?就是在执行Result之前将我们的成员变量user的引用(可能已经被修改了)重新放入到栈顶:
需要修改配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="default" namespace="/" extends="struts-default" abstract="false"> <interceptors>
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<!-- 需要传入refreshModelBeforeResult为true,默认为false -->
<interceptor-ref name="modelDriven">
<param name="refreshModelBeforeResult">true</param>
</interceptor-ref>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
</interceptors> <action name="loginAction" class="struts_practice_001.LoginAction" method="login">
<result>/success.jsp</result>
<result name="input">/login.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package> </struts>
可以使用<s:debug />标签在结果jsp页面查看值栈中的数据已经被刷新为新查询出来的user对象。
总结一下:
1.ModelDriven的实现需要实现一个叫做ModelDriven的接口,然后在getModel()返回一个压入栈顶的对象。
2.如果中间修改了这个Model变量的引用,就需要在执行Result前刷新,所谓刷新就是将最新的Model对象压入栈顶。(需要注意的是如果不是修改的引用的话根本没必要进行刷新,因为只要引用相同的话就可以顺着这个引用找过来,找到的属性还是最新的属性,因为它们只是多个指针指向的堆中的同一块对象内存)
三、ModelDriven的原理
ModelDriven的实现依靠ModelDrivenInterceptor,ModelDrivenInterceptor代码剖析:
/**
* ModelDrivenInterceptor:
* 这个拦截器的作用是将一个对象放到ValueStack的栈顶暴露其属性以便直接访问
*/
public class ModelDrivenInterceptor extends AbstractInterceptor { //默认是不刷新的
protected boolean refreshModelBeforeResult = false; //配置的时候可以传入refreshModelBeforeResult参数设置是否需要在执行Result前刷新
public void setRefreshModelBeforeResult(boolean val) {
this.refreshModelBeforeResult = val;
} @Override
public String intercept(ActionInvocation invocation) throws Exception {
//取得当前的action实例
Object action = invocation.getAction(); //判断action是否实现了ModelDriven接口
if (action instanceof ModelDriven) {
//将action实例转为ModelDriven实例
ModelDriven modelDriven = (ModelDriven) action;
//获取值栈
ValueStack stack = invocation.getStack();
//获取Model
Object model = modelDriven.getModel();
//可能是为了避免空指针之类的吧,所以喽,ModelDriven拦截器不会自动创建对象(需注意与action成员变量有区别)
if (model != null) {
//将Model放到值栈的栈顶
stack.push(model);
}
//判断是否需要在执行结果之前之前刷新
if (refreshModelBeforeResult) {
//如果需要刷新的,添加一个在执行Result之前要执行的回调对象(对象中有一个回调函数)
//我们只需要知道传入的这个对象的beforeResult():void方法要在执行Result之前被调用
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
} /**
* Refreshes the model instance on the value stack, if it has changed
* 如果在
*/
protected static class RefreshModelBeforeResult implements PreResultListener {
//原始Model对象
private Object originalModel = null;
//当前的Action实例
protected ModelDriven action; public RefreshModelBeforeResult(ModelDriven action, Object model) {
this.originalModel = model;
this.action = action;
} //在执行结果之前调用的回调方法
public void beforeResult(ActionInvocation invocation, String resultCode) {
//获得值栈
ValueStack stack = invocation.getStack();
CompoundRoot root = stack.getRoot(); //假设需要刷新
boolean needsRefresh = true;
//拿到最新的Model对象
Object newModel = action.getModel(); // Check to see if the new model instance is already on the stack
//检查如果这个最新的Model可以在栈中找得到,说明根本就没变,所以就不用刷新了
for (Object item : root) {
if (item.equals(newModel)) {
needsRefresh = false;
}
} // Add the new model on the stack
//如果需要将最新的Model对象压入栈顶的话
if (needsRefresh) { // Clear off the old model instance
//首先移除原来的Model对象
if (originalModel != null) {
root.remove(originalModel);
}
//然后将最新的Model对象压入栈顶
if (newModel != null) {
stack.push(newModel);
}
}
}
}
}
Struts2拦截器之ModelDrivenInterceptor的更多相关文章
- Struts2拦截器之FileUploadInterceptor
一.它能做什么? 借助于这个拦截器我们可以实现文件的上传和下载功能. 理论部分: struts2的文件上传下载功能也要依赖于Apache commons-fileupload和Apache commo ...
- Struts2拦截器之DefaultWorkflowInterceptor
一.DefaultWorkflowInterceptor是什么 首先说这东西是干嘛来的,在action中可以对传进来的数据进行验证,方法是实现Validateable接口的validate():voi ...
- Struts2拦截器之ExceptionMappingInterceptor(异常映射拦截器)
一.异常拦截器是什么? 异常拦截器的作用是提供一个机会,可以设置在action执行过程中发生异常的时候映射到一个结果字符串而不是直接中断. 将异常整合到业务逻辑中,比如在分层系统的调用中可以从底层抛出 ...
- Struts2拦截器的执行过程浅析
在学习Struts2的过程中对拦截器和动作类的执行过程一度陷入误区,特别读了一下Struts2的源码,将自己的收获分享给正在困惑的童鞋... 开始先上图: 从Struts2的图可以看出当浏览器发出请求 ...
- Struts2拦截器总结<转>
由于项目中在登录跳转到其他应用程序模块的时候有用到拦截器,因此查看了一下相关资料. 原文地址:http://blog.csdn.net/sendfeng/article/details/4248120 ...
- Struts2 拦截器具体配置过程
拦截器差点儿遍布每个程序中,所以贴出拦截器配置的具体过程,希望可以帮到大家. Struts2 拦截器具体配置过程 <interceptors> <!-- 先定义拦截器 --> ...
- Struts2拦截器详解
一.Struts2拦截器原理: Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 拦截器对象,然后串成一个列 ...
- 转载 - Struts2 拦截器详细配置过程
出处:http://www.blogjava.net/zzzlyr/archive/2009/10/12/297998.html Struts2 拦截器详细配置过程 1:所有拦截器的超级接口Inter ...
- Struts2 拦截器配置以及实现
@(Java ThirdParty)[Struts|Interceptor] Struts2 拦截器配置以及实现 Struts2的拦截器应用于Action,可以在执行Action的方法之前,之后或者两 ...
随机推荐
- Android开源项目(二)
第二部分 工具库 主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过 ...
- Effective Java 读书笔记之七 通用程序设计
一.将局部变量的作用域最小化 1.在第一次使用变量的地方声明 2.几乎每个变量的声明都应该包含一个初始化表达式:try-catch语句是一个例外 3.使方法小而集中是一个好的策略 二.for-each ...
- Android学习笔记(十)——ListView的使用(上)
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! ListView绝对可以称得上是 Android中最常用的控件之一,ListView允许用户通过手指上下滑动的 ...
- JavaScript引用类型
引用类型虽然看起来和类很相似,但是它们却是不同的概念,引用类型的值,也就是对象是引用类型的一个实例.在Js中引用类型主要有Object,Array,Date,正则,Function等. 数组Array ...
- TP中手动加载类库
加载第三方类库,包括不符合命名规范和后缀的类库,以及没有使用 命名空间或者空间和路径不一致的类库.可手动加载. // 导入Org类库包 Library/Org/Util/Date.class.php类 ...
- Qt 官方一键动态发布技能
苦找了好几天动态库,程序可以运行了,结果没有图标还是少了运行库很苦恼,发现Qt 官方有一键动态发布功能感觉自己萌萌的,来自qt吧亲测可用. 集成开发环境 QtCreator 目前生成图形界面程序 ex ...
- phpcms评论框iframe无法自适应问题
问题背景: 之前用友言的时候改过网站的ip地址,改成127开头的了.但是协同开发的时候别人用的还是localhost. 结果在用评论的时候iframe死活不能自适应,看了一下源代码v9本身已经写过if ...
- JustMock Lite (Free Mocking Framework For .net)
通过 Nuget 安装 2. 官网下载(官网不行点这里) 3. 帮助文档 商业版和免费版区别概览 MockingContainer 测试类准备:一般来说也是业务类 public class C ...
- ASP.NET Web API与Rest web api
ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of ...
- Spring4 学习笔记
[9]SpEL语法 [10]Bean的生命周期:(五步)