繼上篇博客介紹了值傳遞的幾種形式,這篇博客,來講說struts2是如何實現的?
有這麼兩個概念和modelDriven實現有關:ValueStack,ModelDrivenInterceptor。html
首先先介紹如下ModelDrivenInterceptor,該攔截器處於defaultStack第九的位置。ModelDrivenInterceptor攔截器主要作的事就是調用Action的getModel()方法而後把返回的model壓入值棧。
下面是該攔截器intercept方法源碼:java
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) { ModelDriven modelDriven = (ModelDriven) action; ValueStack stack = invocation.getStack(); Object model = modelDriven.getModel(); if (model != null) { stack.push(model); } if (refreshModelBeforeResult) { invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); } } return invocation.invoke(); }
此方法就是就是把getModel方法返回的結果壓入值棧而已,咱們通常實現這個接口是利用壓入值棧的model對象接收從頁面提交過來的數據,由於Action也是在值棧中,而struts2在賦值參數的時候是在值棧從棧頂往棧底尋找有相應setter方法的對象,而這時model壓入了值棧,它是處於棧頂的,因此從頁面提交過來的參數也就被model對象接收了。服務器
這個ValueStack和 struts的ognl是分不開的。(valueStack是接口,ognl實現了該接口)
ValueStack實際上就是對OGNL的封裝,OGNL主要的功能就是賦值與取值,Struts2正是經過ValueStack來進行賦值與取值的!ide
ValueStack是一個接口,而OgnlValueStack是strtus2中的缺省實現。ValueStack中的數據,分兩個部分存放:root和context(這與OGNL中的概念一致),同時ValueStack暴露相關的接口:this
void setValue(String expr, Object value);spa
Object findValue(String expr);.net
用來經過OGNL表達式對ValueStack中的數據進行操做!code
ValueStack中的root對象是CompoundRoot,CompoundRoot繼承了ArraryList,提供了額外的方法:push()和pop()方法,用來對root對象中所包含的數據進行存取!htm
public class CompoundRoot extends ArrayList { public CompoundRoot() { } public CompoundRoot(List list) { super(list); } public CompoundRoot cutStack(int index) { return new CompoundRoot(subList(index, size())); } public Object peek() { return get(0); } public Object pop() { return remove(0); } public void push(Object o) { add(0, o); } }
正是經過這兩個方法,CompoundRoot變成了一個棧結構!壓棧操做,將致使對象被放到CompoundRoot的第0個元素上(第0個元素 是棧頂),其它對象被依次日後移動;出棧操做,將致使CompoundRoot的第0個元素被移除(即棧頂元素被彈出),其它對象被依次往前移動!對象
OGNL不支持多個root對象,而struts2可以支持多個root對象,它對OGNL作了擴展。
若是某個OGNL表達式被傳遞給ValueStack(即調用ValueStack的setValue或findValue方法),而表達式中包含 有對root對象的訪問操做,ValueStack將依次從棧頂往棧底搜索CompoundRoot對象中所包含的對象,看哪一個對象具備相應的屬性,找到 以後,馬上返回。
這裏的存是:客戶端請求中的參數如何被 「存」 進 ValueStack,例如:添加操做;而 「取」 是指服務器查詢數據,如何回顯到前臺頁面,例如 更新操做。
接下來,咱們看 存 的實現,其實就是博客開篇提到的,三種方法,一個原則:前臺 控件的name必須是和實體屬性名稱是一致的。這裏再也不贅述。
主要是看 「取」 的實現。
服務器端,咱們須要手動將model 壓入 ValueStack:ActionContext.getContext().getValueStack().push(××);
public class UserAction { //查看用戶的詳細信息 public String detail() { User u = new User(); u.setUsername("wyx"); ActionContext.getContext().getValueStack().push(u); return "update"; } }
在JSP中: 對應的JSP使用 struts2標籤 + ognl 來取。
username:<input type="text" name="username" value="<s:property value="username"/>"> <br/>
或者:
<s:textfield name="username"/>
因此struts2的modelDriven機制: 一、客戶端請求:當一個請求過來,首先被modelDriveInterceptor攔截,執行getModel方法,壓入valueStack,ValueStack 將請求的值和壓入的model進行對比賦值; 二、服務端回發:咱們須要把model push進ValueStack。前臺使用 struts2標籤 + ognl來接受,解析。