一、 ModelDriven的运行机制
大家都知道前台表单数据向后台传递的时候,调用的Action会实现ModelDriven接口。伪码如下:
VO伪码:
public class User {
private String userName;
private String password;
//setter and getter
//....
}
Action伪码:
public class UserAction implements ModelDriven {
private User user = new User();
public String addUser() {
//相应的业务逻辑
}
@Override
public Object getModel() {
return user;
}
}
JSP伪码:
<form action="xxx/user-add.action" method="post">
username:<input type="text" name="username" />
password:<input type="text" name="password" />
<input type="submit" name="submit" value="添加" />
</form>
上面的代码相信大家非常熟悉,但是大家知道Strusts是如何把表单的值填到VO中的?如果你确实无法回答,那么建议认真往下读。
用过Struts的人一定都听说过值栈(后面还会专门介绍),ModelDriven背后的机制正是VlaueStack。JSP页面上的username/password能够被直接赋给user对象,这证明user对象是ValueStack中的一个root对象。那么,user对象是怎么进入ValueStack的呢?答案就是ModelDrivenInterceptor,拦截器大家一定也听说过,在这个拦截器中,会判断当前要调用的Action对象是否实现了ModelDriven接口,如果是,这调用getModel方法,并把返回值压入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) { //判断是否实现ModelDriver接口
ModelDriven modelDriven = (ModelDriven) action;
ValueStack stack = invocation.getStack();
Object model = modelDriven.getModel();
if (model != null) {
stack.push(model); //将Action中getModel()方法返回的对象压入值栈
}
//下面这句条件判断有什么作用呢,请继续往下看
if (refreshModelBeforeResult) {
invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
我们通过一个例子来看下为什么要refreshModelBeforeResult。
Action伪码:
public class UserAction implements ModelDriven {
private User user = new User();
public String viewUser() {
//相应的业务逻辑
user = userService.viewUser(); //从数据库取出数据封装到user对象中
return "更新页面";
}
@Override
public Object getModel() {
return user;
}
}
JSP伪码:
<form action="xxx/user-update.action" method="post">
username:<input type="text" name="username" value="<s:property value="username" />" />
password:<input type="text" name="password" value="<s:property value="username" />" />
<input type="submit" name="submit" value="更新" />
</form>
在更新操作钱,肯定需要先获取到数据,如果没有if(refreshModelBeforeResult),user对象通过getModel()方法被压入到ValueStack中,这时候,UserAction和ValueStack都指向同一个user对象,但紧接着,UserAction中的user被一个新的user对象覆盖,这时候,UserAction和ValueStack不再指向同一个user对象!ValueStack中仍是旧的user对象,而UserAction中是最新的user对象,但是我们知道,在jsp页面访问的都是ValueStack中的user对象,所以它的属性都将是空的。
通过以上的分析,可以猜测,通过if(refreshModelBeforeResult)最终要将最新的值压入ValueStack。
相关源码:
// Add the new model on the stack
if (needsRefresh) {
// Clear off the old model instance
if (originalModel != null) {
root.remove(originalModel);
}
if (newModel != null) {
stack.push(newModel);
}
}
即将酒的model从ValueStack中移除,将新的model压入ValueStack!
来源:oschina
链接:https://my.oschina.net/u/991868/blog/202500