SSH框架中不为人知的细节(一)

跟風遠走 提交于 2019-12-01 12:48:58

一、 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!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!