Struts2中的ModelDriven机制及其运用(转)
所谓ModelDriven,意思是直接把实体类当成页面数据的收集对象。比如,有实体类User如下:
package cn.com.leadfar.struts2.actions; public class User { private int id; private String username; private String password; private int age; private String address; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getId() { return id; } public void setId(int id) { this.id = id; } } |
假如要写一个Action,用来添加User。
第一种做法是直接在Action中定义所有需要的属性,然后在JSP中直接用属性名称来提交数据:
UserAction:
public class UserAction { private int id; private String username; private String password; private int age; private String address; public String add(){ User user = new User(); user.setId(id); user.setUsername(username); user.setPassword(password); user.setAge(age); user.setAddress(address); new UserManager().addUser(user); return "success"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } |
add_input.jsp:
<form action="test/user.action" method="post"> <input type="hidden" name="method:add"> username:<input type="text" name="username"> <br/> password:<input type="text" name="password"> <br/> age:<input type="text" name="age"> <br/> address:<input type="text" name="address"> <br/> <input type="submit" name="submit" value="添加用户"> </form> <br/> |
上述做法不好之处是:如果实体类的属性非常多,那么Action中也要定义相同的属性。
第二种做法是将User对象定义到UserAction中,然后在JSP中通过user属性来给user赋值:
UserAction:
public class UserAction { private User user; public String add(){ new UserManager().addUser(user); return "success"; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } |
add_input.jsp:
<form action="test/user.action" method="post"> <input type="hidden" name="method:add"> username:<input type="text" name="user.username"> <br/> password:<input type="text" name="user.password"> <br/> age:<input type="text" name="user.age"> <br/> address:<input type="text" name="user.address"> <br/> <input type="submit" name="submit" value="添加用户"> </form> <br/> |
这种做法不好的地方是:JSP页面上表单域中的命名变得太长
第三种做法是利用ModelDriven机制,让UserAction实现一个ModelDriven接口,同时实现接口中的方法:getModel()。如下所示:
public class UserAction implements ModelDriven{ private User user; @Override public Object getModel() { if(user == null){ user = new User(); } return user; } public String add(){ new UserManager().addUser(user); return "success"; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } |
JSP的代码如下:
<form action="test/user.action" method="post"> <input type="hidden" name="method:add"> username:<input type="text" name="username"> <br/> password:<input type="text" name="password"> <br/> age:<input type="text" name="age"> <br/> <input type="submit" name="submit" value="添加用户"> </form> <br/> |
可见,第三种做法是比较好的,Action和JSP写起来都比较简单。
ModelDriven背后的机制?
ModelDriven背后的机制就是ValueStack。界面通过:username/age/address这样的名称,就能够被直接赋值给user对象,这证明user对象正是ValueStack中的一个root对象!
那么,为什么user对象会在ValueStack中呢?它是什么时候被压入ValueStack的呢?答案是:ModelDrivenInterceptor(关于Interceptor的概念,请参考后续章节的说明)。ModelDrivenInterceptor是缺省的拦截器链的一部分,当一个请求经过ModelDrivenInterceptor的时候,在这个拦截器中,会判断当前要调用的Action对象是否实现了ModelDriven接口,如果实现了这个接口,则调用getModel()方法,并把返回值(本例是返回user对象)压入ValueStack。
请看ModelDrivenInterceptor的代码:
public class ModelDrivenInterceptor extends AbstractInterceptor { protected boolean refreshModelBeforeResult = false; public void setRefreshModelBeforeResult(boolean val) { this.refreshModelBeforeResult = val; } @Override public String intercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); if (action instanceof ModelDriven) { ModelDriven modelDriven = (ModelDriven) action; ValueStack stack = invocation.getStack(); Object model = modelDriven.getModel(); if (model != null) { stack.push(model); } if (refreshModelBeforeResult) { invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); } } return invocation.invoke(); } |
从ModelDrivenInterceptor中,即可以看到model对象被压入ValueStack中!
其中的refreshModelBeforeResult是为了接下来描述的一个问题而提供的解决方法。
理解常见的陷阱及其解决方法
假设我们要更新一个实体对象,那么第一步首先是打开更新界面,请看下述模拟打开更新界面的代码:
public class UserAction implements ModelDriven{ private User user; @Override public Object getModel() { if(user == null){ user = new User(); //user.setUsername("这是原来的User对象"); } return user; } public String updateInput(){ //根据ID,查询数据库,得到User对象 user = new UserManager().findUserById(user.getId()); return "update_input"; } |
上述代码中,new UserManager().findUserById(user.getId());这一行,将从数据库中查询相应的记录,同时转换为User对象返回。而return “update_input”;将转向更新显示页面。
更新页面如下:
<form action="test/user.action" method="post"> <input type="hidden" name="method:update"> id:<input type="text" name="id" value="<s:property value="id"/>"> <br/> username:<input type="text" name="username" value="<s:property value="username"/>"> <br/> password:<input type="text" name="password" value="<s:property value="password"/>"> <br/> age:<input type="text" name="age" value="<s:property value="age"/>"> <br/> address:<input type="text" name="address" value="<s:property value="address"/>"> <br/> <input type="submit" name="submit" value="更新用户"> </form> <br/> |
上述代码运行起来之后,你在更新界面上将看不到数据(id属性有值,其它属性无显示)。关键的原因是在执行到updateInput之前,user对象(在getMode()方法中创建的对象)被压到ValueStack中,这时候,UserAction和ValueStack都指向同一个user对象;但紧接着,UserAction中的user被一个新的user对象覆盖,这时候,UserAction和ValueStack不再指向同一个user对象!ValueStack中是旧的user对象,而UserAction中是新的user对象!我们在JSP中,直接通过username/address等直接访问,当然是要访问ValueStack中的旧user对象,所以它们的属性都是空的(id属性除外)!
理解上述问题很重要,当你理解了问题,那么问题的解决方法就可以有很多了:
比如,你可以把新对象的属性拷贝到旧对象上;比如,你可以先把旧对象从ValueStack中移除,然后再把新对象压入ValueStack等……
在最新的struts2版本中,ModelDrivenInterceptor提供了一个配置参数:refreshModelBeforeResult,只要将它定义为true,上述问题就被解决了!struts2的解决方案就是:先把旧的model对象从ValueStack中移除,然后再把新的model对象压入ValueStack!
Struts2中的ModelDriven机制及其运用(转)的更多相关文章
- Struts2中的ModelDriven机制及其运用
所谓ModelDriven,意思是直接把实体类当成页面数据的收集对象.比如,有实体类User如下: package cn.com.leadfar.struts2.actions; public cla ...
- Struts2中的ModelDriven机制及其运用、refreshModelBeforeResult属性解决的问题
1.为什么需要ModelDriven? 所谓ModelDriven,意思是直接把实体类当成页面数据的收集对象.比如,有实体类User如下: package cn.com.leadfar.struts2 ...
- struts2中的ModelDriven使用
http://www.cnblogs.com/Topless/archive/2012/01/17/2324980.html 例子都为struts2中的文档例子 JSP提交数据: <s:fo ...
- Struts2中的ModelDriven接口
若没有实现ModelDriven的接口,Controll的代码会比较冗余,不能实现Controll和Model代码的分离 下面是没有实现ModelDriven接口的SuggestAction pack ...
- Struts2中请求参数的接收方式和ModelDriven机制及其运用
odelDriven 为什么需要ModelDriven 所谓ModelDriven,意思是直接把实体类当成页面数据的收集对象.比如,有实体类User如下: package cn.com.leadfar ...
- Struts2中数据封装机制
Struts2当中数据封装的三种机制:属性驱动.标签驱动.模型驱动.下面来一一介绍. 一.属性驱动 1.需要提供对应属性的set方法进行数据的封装. 2.表单的哪些属性需要封装数据,那么在对应的Act ...
- 【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
一.struts2系统验证 1.基于struts2系统验证的方式实际上就是通过配置xml文件的方式达到验证的目的. 2.实际上系统校验的方法和手工校验的方法在底层的基本实现是相同的.但是使用系统校验的 ...
- 简单理解Struts2中拦截器与过滤器的区别及执行顺序
简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...
- Struts2中的 配置文件
struts2中涉及到的配置文件有: web.xml.struts.xml.struts.properties.default.properties.struts-default.xml web.xm ...
随机推荐
- ububtu 14.04 问题集合
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4168168.html 1.Chromium 中的flash插件问题: sudo apt-ge ...
- JS数组(Array)处理函数总结
1.concat() 连接两个或更多的数组该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本.例如: <script type="text/javascript"&g ...
- PHP高级笔记汇总
一.PHP日期 PHP的date()函数用于格式化时间或日期.PHP Date()函数可把时间戳格式化为可读性更好的日期和时间.语法:date(format,timestamp)format:必需.规 ...
- 三、MongoDB的创建、更新和删除
一.MongoDB的下载.安装与部署 二.MongoDB的基础知识简介 三.MongoDB的创建.更新和删除 概要 下面开始学习MongoDB最重要也是最基础的部分:C(创建)R(查询)U(更新)D( ...
- 【Weblogic】--Weblogic的部署方式和缓存
参考网址: http://dead-knight.iteye.com/blog/1938882 Weblogic11g部署web应用,有三种方式,非常简单,但是很多新手部署总是出现若干错误,不知道如何 ...
- 访问svc 文件,编译器错误消息: CS0016,未能写入输出文件
编译错误 说明: 在编译向该请求提供服务所需资源的过程中出现错误.请检查下列特定错误详细信息并适当地修改源代码. 编译器错误消息: CS0016: 未 ...
- Python可以做什么?
Python是一个优秀的程序语言,PYthon的应用角色几乎是无限的,你可以在任何场合应用Python. 1 系统编程 Python提供对系统管理的内部接口,可以搜索文件和目录,可以运行其他程序 Py ...
- android----Java DES加密算法工具类
DESUtil类 public class DESUtil { private static byte[] iv = {0x12, 0x34, 0x56, 0x78, (byte) 0x90, (by ...
- SQLite之写一个表
1.首先你需要一个路径. 获取document目录并返回数据库目录 - (NSString *)dataFilePath{ NSArray *paths = NSSearchPathForDirect ...
- Swift global function(count indexOfObject contains...)
当你在使用Swift时会发现一些常用的函数不!见!了! 比如 String: s.count() s.contains() Array: a.indexOfObeject(t:<T> ...