锁定老帖子 主题:关于webwork字段值自动邦定的困惑
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-07-08
UserService.java
/* * Created on 2004-7-8 * UserService.java */ package example.cuid; import java.util.Collection; import java.util.HashMap; import java.util.Map; import example.register.User; /** * @author moxie-qac * achqian@yahoo.com.cn * */ public class UserService { private static UserService userService = null; private static Map users = new HashMap();; static { User user_1 = new User();; user_1.setId("1");; user_1.setUsername("user_1");; User user_2 = new User();; user_2.setId("2");; user_2.setUsername("user_2");; User user_3 = new User();; user_3.setId("3");; user_3.setUsername("user_3");; users.put(user_1.getId();,user_1);; users.put(user_2.getId();,user_2);; users.put(user_3.getId();,user_3);; } private UserService();{ } public static UserService getUserService();{ if(userService == null);{ userService = new UserService();; } return userService; } public User[] ListAllUsers();{ Collection collUses = users.values();; User[] arrUsers = new User[collUses.size();]; collUses.toArray(arrUsers);; return arrUsers; } public User getUserById(String userId);{ return (User); users.get(userId);; } public void update(User user);{ users.put(user.getId();,user);; } } editUser.vm <html> <head><title>Edit user</title></head> <body> Edit:<p> <form name="form1" action="$req.contextPath/cuid/updateUser.action" method="POST"> UserId:<input type="text" name="user.id" value="$user.id"><br> UserName:<input type="text" name="user.username" value="$user.username"> <p> <input type="submit" name="submit">&& <input type="reset" name="restet"> </form> </body> listAllUsers.vm <html> <head><title>List all users</title></head> <body> List all users: <table width="70%"> <tr><td>userId</td><td>username</td><td></td> </tr> #foreach( $user in $users ); <tr> <td>$user.id</td> <td>$user.username</td> <td><a href="$req.contextPath/cuid/viewUser.action?userId=$user.id">[ EDIT ]</a></td> </tr> #end </body> |
|
返回顶楼 | |
发表时间:2004-07-08
明白了, moxie的方法是可行的.
我的错误在于对hibernate的认识不足(因为我的问题是在webwork+sprint+hibernate的组合框架中产生的,我现在是就是论事). 之前我认为要update一个PO对象, 必需经过下面的步骤: 1.根据ID从数据库中取出PO; 2.根据页面中的数据更新PO(这一步由webwork自动完成); 3.保存到数据库. 实际上在hibernate中也可以用下面的步骤更新PO: 1.新产生一个PO, 该PO没有任何数据值; 2.用页面数据更新PO, 这里页面中的数据包括PO的ID值; 3.保存到数据库,因为hibernate根据PO的ID可以判断是update还是insert. 说到这里,我又发现moxie的方法只能对付一次更新PO所有值的情况, 如果在某次更新中只修改用户密码(页面中只有两个值user.id, user.password), 这时用moxie的方法, 会将user的其它值比如user.name清空, 这不是我想要的. 另外,一般User对象是一个接口, 它有getId() 方法, 但没有setId()方法(因为id是由hibernate设置的,不是一个公有方法) , 这时moxie的方法也行不通 所以问题还是没解决. ~~ |
|
返回顶楼 | |
发表时间:2004-07-08
jxb8901 写道 moxie的方法只能对付一次更新PO所有值的情况, 如果在某次更新中只修改用户密码(页面中只有两个值user.id, user.password), 这时用moxie的方法, 会将user的其它值比如user.name清空, 这不是我想要的.
这个时候,你可以在页面将user.name设置为hidden就ok了。 jxb8901 写道 另外,一般User对象是一个接口, 它有getId() 方法, 但没有setId()方法(因为id是由hibernate设置的,不是一个公有方法) , 这时moxie的方法也行不通 这时,也许你的领域对象就不能完全充当ForBean的作用了,你就要考虑是否需要DTO去传递数据。 我这个例子也只是做演示用,实际开发的需求也许会很复杂,但采用一些小的技巧,我想都能满足要求的。 |
|
返回顶楼 | |
发表时间:2004-07-08
moxie 写道 jxb8901 写道 moxie的方法只能对付一次更新PO所有值的情况, 如果在某次更新中只修改用户密码(页面中只有两个值user.id, user.password), 这时用moxie的方法, 会将user的其它值比如user.name清空, 这不是我想要的.
这个时候,你可以在页面将user.name设置为hidden就ok了。 如果出现zgd所说的用户有一对多关系(比如user.getRoles()), 这种方法还是不适用. moxie 写道 jxb8901 写道 另外,一般User对象是一个接口, 它有getId() 方法, 但没有setId()方法(因为id是由hibernate设置的,不是一个公有方法) , 这时moxie的方法也行不通 这时,也许你的领域对象就不能完全充当ForBean的作用了,你就要考虑是否需要DTO去传递数据。 没有好的办法时看来只能折中了. ~~ |
|
返回顶楼 | |
发表时间:2004-07-09
我不明白为什么不先load一次,再做更新,这样不就可以避免你说的所有问题了吗?
通常一定要先load一次,否则的话,你怎么处理要更新的数据正好被别人删除等异常情况? 一对多关系的通常维护关系都是设置在多的一段(inverse="true"),更新不会影响到其对应多的元素。 嫌代码麻烦的话,写一个abstract class,然后所有的View, Create, Update, Delete User action都extends它就可以了: public abstract class UserAction implements Action{ private User user; private String userId; public User getUser(); { if(user != null); return user; if(userId != null); { user = getUserService();.loadUserById(userId);; //if user == null throw can not find user exception }else{ user = new User();; } return user; } } |
|
返回顶楼 | |
发表时间:2004-07-12
Quake Wang 写道 我不明白为什么不先load一次,再做更新,这样不就可以避免你说的所有问题了吗?
通常一定要先load一次,否则的话,你怎么处理要更新的数据正好被别人删除等异常情况? 我的意思并不是说不要先load, 事实上肯定应该先load一次. (但moxie的代码是不用先load的,这样会有我在回贴中说的问题), 另外楼上的getUser()的代码在实际使用中会有问题, 因为getUser()方法的第一次调用必定是发生在ParameterInterceptor中对页面参数实行自动邦定的过程中,也就是若页面中有参数user.name时,就会先调用getUser()方法,但此时userId可能还未被ParameterInterceptor邦定到action的userId字段中,所以若要getUser()能正常工作,只有两个方法:1.userId字段的值不依赖于自动邦定,自已从ActionContext中取得,2.做一个通用的IdInterceptor在ParameterInterceptor之前先邦定userId字段. 而方法1就是我说的不够优雅的方法,为什么偏偏这个ID字段要我自己去取呢? 我现在的做法是: private User user; public String create(); { userService.saveUser(user);; return SUCCESS; } public String modify(); { User oldUser = userService.getUserById(getUser();.getId(););; //...手工将user中的字段值复制到oldUser中. //...以前不想嫌麻烦,但有时候还必须如此.因为可精确限定只修改哪些字段 userService.saveUser(oldUser);; return SUCCESS; } public User getUser(); { if (user == null); user = userService.createUser();; return user; } |
|
返回顶楼 | |
发表时间:2004-07-12
这个问题就是没有好办法,除非改写Webwork赋值的这一段代码,首先检查是否存在xxx.id参数,如果有就load,然后set其他的参数。
jxb8901 写道 Quake Wang 写道 我不明白为什么不先load一次,再做更新,这样不就可以避免你说的所有问题了吗?
通常一定要先load一次,否则的话,你怎么处理要更新的数据正好被别人删除等异常情况? 我的意思并不是说不要先load, 事实上肯定应该先load一次. (但moxie的代码是不用先load的,这样会有我在回贴中说的问题), 另外楼上的getUser()的代码在实际使用中会有问题, 因为getUser()方法的第一次调用必定是发生在ParameterInterceptor中对页面参数实行自动邦定的过程中,也就是若页面中有参数user.name时,就会先调用getUser()方法,但此时userId可能还未被ParameterInterceptor邦定到action的userId字段中,所以若要getUser()能正常工作,只有两个方法:1.userId字段的值不依赖于自动邦定,自已从ActionContext中取得,2.做一个通用的IdInterceptor在ParameterInterceptor之前先邦定userId字段. 而方法1就是我说的不够优雅的方法,为什么偏偏这个ID字段要我自己去取呢? 我现在的做法是: private User user; public String create(); { userService.saveUser(user);; return SUCCESS; } public String modify(); { User oldUser = userService.getUserById(getUser();.getId(););; //...手工将user中的字段值复制到oldUser中. //...以前不想嫌麻烦,但有时候还必须如此.因为可精确限定只修改哪些字段 userService.saveUser(oldUser);; return SUCCESS; } public User getUser(); { if (user == null); user = userService.createUser();; return user; } |
|
返回顶楼 | |
发表时间:2004-07-13
http://forum.iteye.com/viewtopic.php?t=6108
|
|
返回顶楼 | |
发表时间:2004-07-16
jxb8901 写道 Quake Wang 写道 我不明白为什么不先load一次,再做更新,这样不就可以避免你说的所有问题了吗?
通常一定要先load一次,否则的话,你怎么处理要更新的数据正好被别人删除等异常情况? 我的意思并不是说不要先load, 事实上肯定应该先load一次. (但moxie的代码是不用先load的,这样会有我在回贴中说的问题), 另外楼上的getUser()的代码在实际使用中会有问题, 因为getUser()方法的第一次调用必定是发生在ParameterInterceptor中对页面参数实行自动邦定的过程中,也就是若页面中有参数user.name时,就会先调用getUser()方法,但此时userId可能还未被ParameterInterceptor邦定到action的userId字段中,所以若要getUser()能正常工作,只有两个方法:1.userId字段的值不依赖于自动邦定,自已从ActionContext中取得,2.做一个通用的IdInterceptor在ParameterInterceptor之前先邦定userId字段. 而方法1就是我说的不够优雅的方法,为什么偏偏这个ID字段要我自己去取呢? 明白了,是我理解错了,前面的代码是如你所分析的那样会出现问题。但是我觉得ID字段做特殊处理,没有什么不太方便的地方,按照你的第一种方法,做一下修改,不要从session里面读取,改到从parameters里面读取: public abstract class UserAction implements Action{ private User user; private UserService userService; public User getUser(); { if(user != null); return user; if(ActionContext.getContext();.getParameters();.get("userId"); != null); { user = getUserService();.loadUserById(ActionContext.getContext();.getParameters();.get("userId"););; //if user == null throw can not find user exception }else{ user = new User();; } return user; } } public class CreateUserAction extends UserAction { public String execute(); { getUserService();.create(getUser(););; return SUCCESS; } } public class UpdateUserAction extends UserAction { public String execute(); { getUserService();.update(getUser(););; return SUCCESS; } } public class DeleteUserAction extends UserAction { public String execute(); { getUserService();.delete(getUser(););; return SUCCESS; } } 这样的代码我觉得很简洁了。 用你说的第二种方法也是不错的选择,自己写一个interceptor,取代掉默认的ParametersInterceptor,先遍历一下,如果有parameter name endsWith Id,那么先stack.setValue。然后再遍历第2次,把所有的parameter set一下。这样的做法唯一的缺点就是需要2次遍历。 不知道大家有没有其他更好的做法。 |
|
返回顶楼 | |
发表时间:2004-07-22
其实规根到底是OGNL的功劳,我对他做了一些扩展
public Object findValue(String expr, Object context); { try { return Ognl.getValue(OgnlUtil.compile(expr);, context);; } catch (OgnlException e); { return null; } } /** * 动态装订数据 * @param fieldName * @param value * @param destObject */ public void setValue(String fieldName, Object value, Object destObject); { java.util.Map context = Ognl.createDefaultContext(destObject);; OgnlUtil.setProperty(fieldName, value, destObject, context);; } |
|
返回顶楼 | |