论坛首页 Java版 Webwork

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

浏览 17656 次
该帖已经被评为精华帖
作者 正文
时间:2004-07-08
下面是我向moxie请教时的提问:
引用
moxie,您好!

看了你的<webwork教程>获益良多,我使用webwork也有一段时间了,但最近一直碰到一个问题,总无法解决,特向你请教:

在你的教程中讲到了Field driven action, 并举了一个用户注册的例子, 其中页面上的user.name值可以被WW自动邦定到action中的user对象中. 在你的例子中,getUser()方法返回的是一个new User()对象,但如果是修改用户属性,此时getUser()应该返回用户正在编辑的user, 那么getUser()如何得到该对象呢? 在我想来有两个方法:
一是当要修改用户属性时,先将要修改的user保存在session中,那么getUser()方法就可以从session中取得正在编辑的user, 这种方法有其局限性, 我不太喜欢;
第二种方法是在getUser()方法内部,直接从ActionContext中取得userId参数,并调用service的getUserById()方法来取得user, 但这种做法我总感觉不够优雅, 这个问题困扰我很久了,一直不知如何是好? 不知你有没有更好的方法?


下面是moxie的回复:
引用
jxb,您好!
我想你应该是没有完全理解ValueStack(值堆栈,在XWork中,它是OgnlValueStack)。当你提交一个表单到action中,在它执行之前,由框架去取得你的Action,并实例化这个Action对象,再将这个Action对象放入它的值堆栈中。
这时候,你在做编辑的时候,它一定会有原始的数据,假设这个数据对象就是user,同时假设这个数据就是从数据库中取得的。
你要编辑这个user对象的数据,当然你的视图(也许是页面)要获取原始的数据。如何获取?你可以通过EL(表达式语言)从OgnlValueStack中获取。你的EL:user.username,它就是相当于调用Action对象的getUser().getUsername();方法。通过这种方式,你可以在视图中取得原始数据。
到这里,我想你都能明白。但请注意下面:
在你对原始数据进行更新时,你希望这个更新的数据同步到user对象中。这时,你仍然是通过EL,进行值的设置(注意:前面是值的获取)。你的EL:user.username,它这是相当于调用代码:getUse.setUsername(你更新的值)。

WebWork的简洁、灵活,很多都是来源于EL和ValueStack。

不知道我的回答是否能解决你的问题,更好的解决方式是通过简单的代码来实现,你可以写一些程序来验证,当然,如果有疑问我也可以帮忙完善。


谢谢moxie的及时回复, 但可能我没有表达清楚我的问题,我想再用代码重新说明一下,同时为了再次得到moxie的及时回复,我特地将这个问题拿到论坛中请大家帮我解域,也免得邮件来邮件去的,等得我心焦^_^
[code:1] //user.detail.vm

<input type="text" name="user.name" value="$!user.name"/>
<input type="hidden" name="userId" value="$!user.id"/>[/code:1]
[code:1] //ViewUserAction.java

private User user;
private String userId;

public String execute() {
return SUCCESS;
}
public void setUserId(String userId) { this.userId = userId; }

public User getUser() {
if (user == null) {
user = userService.getUserById(userId);
//采用第一种方法时才需要下面的语句
ActionContext.getActionContext().getSession().put("__user__", user);
}
return user;
}[/code:1]
[code:1] //CreateUserAction.java

//创建一个空的用户对象
private User user = userService.createUser();

public String execute() {
userService.save(user);
return SUCCESS;
}

public User getUser() { return user;}[/code:1]
[code:1] //ModifyUserAction.java

private User user;

public String execute() {
userService.save(user);
return SUCCESS;
}

public User getUser() {
//方法1:
//当用户进入user.detail.vm时,ViewUserAction.java已将用户
//正在查看的对象保存到了session中所以现在可以取出
return (User)ActionContext.getActionContext().getSession().get("__user__");

//方法2:
if (user == null) {
String userId = getParameter("userId");
user = userService.getUserById(userId);
}
return user;
}[/code:1]
我的问题是: 在ModifyUserAction.java中getUser()方法应该如何实现?
我给出的方法1有特定的限制,比如只能允许用户在一个页面中一次只能修改一个用户的信息, 另外ViewUserAction与ModifyUserAction也有一种隐含的藕合,所以我不愿意采用该方法,第二种方法要我自己从parameters中取出userId这个参数,然后转换为user对象, 因为页面中有许多参数存在于parameters中,其它参数都可以由webwork自动邦定,可为什么userId这个参数要这么特殊呢? 这就是我觉得不爽的地方. 另外我也想到能不能用interceptor解决,感觉这个interceptor做出并不能通用,所以和第二种方案还是同一回事.
   
时间:2004-07-08
其实你只要将你传递的参数userId更改成user.userId就行了
[code:1]
user = userService.getUserById(user.getUserId());

[/code:1]
   
0 请登录后投票
时间:2004-07-08
我认为你的方法行不通,因为user对象的userId还没有被ParameterInteceptor邦定到user中, 除非有两个ParameterInteceptor, 前一个负责邦定id, 后一个负责邦定其它参数, 或者ParameterInteceptor在邦定参数时能设定顺序, 也就是能先邦定id, 再邦定其它参数. 不过都是瞎想,行不通.
   
0 请登录后投票
时间:2004-07-08
jxb8901 写道
我认为你的方法行不通,因为user对象的userId还没有被ParameterInteceptor邦定到user中, 除非有两个ParameterInteceptor, 前一个负责邦定id, 后一个负责邦定其它参数, 或者ParameterInteceptor在邦定参数时能设定顺序, 也就是能先邦定id, 再邦定其它参数. 不过都是瞎想,行不通.


我都测试过了,怎会不行呢?
比如因为你修改一个用户的资料时候,肯定要有ID传过来,如果你传的是userId,那你肯定要自己转换,如果你传的是user.userId,系统会自动帮你将这参数绑定到你的变量user中去。
例如
[code:1]http://localhost:8080/edit_user.action?user.userId=12345[/code:1]你在edit_user.action中
直接写
[code:1]user = getUserById(user.getUserId());[/code:1]就行了
   
0 请登录后投票
时间:2004-07-08
不知能不能把你的getUser()的代码贴出来,我们对着代码好说话一点, 这样空谈半天, 可能都说的不是同一回事.

能把getUser()的代码贴出来吗? 而且你测试至少应该传两个参数:user.userId,user.name
   
0 请登录后投票
时间:2004-07-08
zgd为什么把回复给删掉了? 我还正在想总算有人看得懂我的问题呢(很担心我表达不清) ^_^
   
0 请登录后投票
时间:2004-07-08
给你抓到了
我看了后来你的回帖
觉得我的问题跟你的问题好像有出入
所以自己开了一篇新帖了

下面是删掉的原贴
--------------------------------------------------------
如果User是一个hibernate的PO的话
把它放在httpSession里不失为一种好方法
页面里直接对httpSession里的user操作
当进行saveAction的时候
从httpSession里拿到的user就能直接用hibernateSession.update回数据库
这也是那个webwork2+hiberate的demo adminapp里的做法
ps,adminapp在这里http://wiki.opensymphony.com/display/WW/Examples

但是比较严重的问题就是不能同时打开两个修改user的页面,另外就是如果不在使用完以后立刻删除该httpSession变量的话就是持续占有服务器内存

如果不用httpSession的话,就必须把user里不需要显示到页面的属性用hidden记录下来,但是如果user有list(一对多或多对多关系)那怎么办呢?这似乎无法解决,折中的解决办法就是把主键id写到hidden里,然后在saveAction里使用select&update的方法(这里可以构造一个formBean),这也并不优雅
   
0 请登录后投票
时间:2004-07-08
你的意思是否是user_detail.jsp 中可以进行用户资料的更改,但是保存是在另外一个页面user_save,
问题是当从user_detail导航到user_save的时候,user_save如何取到user_detail页更改过的user,由user_save负责将这个user存储到数据库。对吗?
不知道我的理解是不是正确?
   
0 请登录后投票
时间:2004-07-08
不完全正确.
1.user_save是一个action类,不是页面
2.不是说user_save如何取到user_detail中的user, 而是说user_detail中的字段值如何自动邦定到user_save中的一个user对象, 其实邦定是webwork自动完成的, 关键是userid如何转换为数据库中的user对象.
如果你没用过webwork,可能不太能理解我提的问题, 如果你愿意的话我可以发一段代码给你.(还是代码好说话)
   
0 请登录后投票
时间:2004-07-08
To:jxb8901
你的问题我能明白,我想是我的回答太抽象,让你误解了。现写的演示代码如下:

//xwork.xml:
[code:1]
<package name="cuid" extends="webwork-default" namespace="/cuid">
<default-interceptor-ref name="params"/>

<action name="listAllUsers" class="example.cuid.ListAllUsersAction" >
<result name="success" type="velocity">
<param name="location">/cuid/listAllUsers.vm</param>
</result>
</action>
<action name="viewUser" class="example.cuid.ViewUserAction" >
<result name="success" type="velocity">
<param name="location">/cuid/editUser.vm</param>
</result>
</action>
<action name="updateUser" class="example.cuid.UpdateUserAction" >
<result name="success" type="chain">
<param name="actionName">listAllUsers</param>
<param name="namespace">/cuid</param>
</result>
</action>
</package>

[/code:1]


ListAllUsersAction.java
[code:1]

/*
* Created on 2004-7-8
* ListAllUsersAction.java
*/
package example.cuid;

import com.opensymphony.xwork.Action;

import example.register.User;

/**
* @author moxie-qac
* achqian@yahoo.com.cn
*
*/
public class ListAllUsersAction implements Action{
private User[] users;

/* (non-Javadoc)
* @see com.opensymphony.xwork.Action#execute()
*/
public String execute() throws Exception {
UserService userService = UserService.getUserService();
users = userService.ListAllUsers();
return SUCCESS;
}

public User[] getUsers(){
return users;
}

}
[/code:1]

ViewUserAction.java
[code:1]
/*
* Created on 2004-7-8
* ViewUserAction.java
*/
package example.cuid;

import com.opensymphony.xwork.Action;

import example.register.User;

/**
* @author moxie-qac
* achqian@yahoo.com.cn
*
*/
public class ViewUserAction implements Action{
private String userId;
private User user;

/* (non-Javadoc)
* @see com.opensymphony.xwork.Action#execute()
*/
public String execute() throws Exception {
UserService userService = UserService.getUserService();
user = userService.getUserById(userId);
return SUCCESS;
}

public void setUserId(String userId){
this.userId = userId;
}

public User getUser(){
return user;
}

}

[/code:1]

UpdateUserAction.java
[code:1]
/*
* Created on 2004-7-8
* UpdateUserAction.java
*/
package example.cuid;

import com.opensymphony.xwork.Action;

import example.register.User;

/**
* @author moxie-qac
* achqian@yahoo.com.cn
*
*/
public class UpdateUserAction implements Action{
private User user = new User();

/* (non-Javadoc)
* @see com.opensymphony.xwork.Action#execute()
*/
public String execute() throws Exception {
UserService userService = UserService.getUserService();
userService.update(user);
return SUCCESS;
}

public User getUser(){
return user;
}
}

[/code:1]
   
0 请登录后投票
论坛首页 Java版 Webwork

跳转论坛:
JavaEye推荐