论坛首页 Java企业应用论坛

关于webwork字段值自动邦定的困惑

浏览 25727 次
该帖已经被评为精华帖
作者 正文
   发表时间: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">&amp;&amp;
<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>

0 请登录后投票
   发表时间: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的方法也行不通

所以问题还是没解决. ~~
0 请登录后投票
   发表时间: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去传递数据。

我这个例子也只是做演示用,实际开发的需求也许会很复杂,但采用一些小的技巧,我想都能满足要求的。
0 请登录后投票
   发表时间: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去传递数据。

没有好的办法时看来只能折中了. ~~
0 请登录后投票
   发表时间: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;
    }
}
0 请登录后投票
   发表时间: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;
}
0 请登录后投票
   发表时间: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;
}
0 请登录后投票
   发表时间:2004-07-13  
http://forum.iteye.com/viewtopic.php?t=6108
0 请登录后投票
   发表时间: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次遍历。

不知道大家有没有其他更好的做法。
0 请登录后投票
   发表时间: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);;
	}
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics