SSH框架中鮮爲人知的細節(一)

1、 ModelDriven的運行機制

    你們都知道前臺表單數據向後臺傳遞的時候,調用的Action會實現ModelDriven接口。僞碼以下:html

VO僞碼:java

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僞碼: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中的?若是你確實沒法回答,那麼建議認真往下讀。ide

    用過Struts的人必定都據說過值棧(後面還會專門介紹),ModelDriven背後的機制正是VlaueStack。JSP頁面上的username/password可以被直接賦給user對象,這證實user對象是ValueStack中的一個root對象。那麼,user對象是怎麼進入ValueStack的呢?答案就是ModelDrivenInterceptor,攔截器你們必定也據說過,在這個攔截器中,會判斷當前要調用的Action對象是否實現了ModelDriven接口,若是是,這調用getModel方法,並把返回值壓入ValueStack。post

ModelDrivenInterceptor的代碼:this

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。spa

Action僞碼:code

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僞碼:orm

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

相關文章
相關標籤/搜索