struts2中的ValueStack

Struts2是通過ValueStack來進行賦值與取值的。
ValueStack實際上就是對OGNL的封裝,OGNL主要的功能就是賦值與取值。

ValueStack中的數據,分兩個部分存放:root和context
同時ValueStack暴露相關的接口(賦值和取值):
void setValue(String expr, Object value);
Object findValue(String expr);
通過OGNL表達式對ValueStack中的數據進行操作。

root

ValueStack中的root對象是CompoundRoot。
CompoundRoot繼承了ArraryList,提供了額外的方法:push()和pop()方法,
用來對root對象中所包含的數據進行存取。
正是通過這兩個方法,CompoundRoot變成了一個棧結構.
壓棧操作,將導致對象被放到CompoundRoot的第0個元素上(第0個元素是棧頂),其它對象被依次往後移動;
出棧操作,將導致CompoundRoot的第0個元素被移除(即棧頂元素被彈出),其它對象被依次往前移動

OGNL只能訪問被壓入堆棧(CompoundRoot)中的元素。
在Struts2中,一個請求在最終到達Action的方法之前,Action對象本身會被壓入
ValueStack的CompoundRoot對象中。
所以Action對象是CompoundRoot對象中的一個元素,可以使用OGNL表達式直接訪問。

在jSP頁面中,使用<s:property value=”ognl表達式”/>標籤,將CompoundRoot棧中的值取出。
在<s:property>標籤中的OGNL表達式,最終會交給ValueStack來解釋。
比如:"username"就是一個OGNL表達式,意思是調用root對象的getUsername()方法。



Context


由於在OGNL中,不支持多個root對象,但在struts2的OGNL的表達式中,
有可能需要訪問到多個毫不相干的對象。這時候,我們把表達式中需要用到的對象放到Map中,
傳遞給OGNL,進行訪問。這個Map對象,稱爲context。

可見valueStack對OGNL進行了擴展,使OGNL表達式可以訪問到多個root對象。

要在表達式中訪問到context中的對象,需要使用“#對象名稱”的語法規則。
#表示將context對象的元素放入到CompoundRoot對象的棧頂。訪問完後,
context對象的元素會從棧頂移出,自動釋放。

當CompoundRoot棧中存在多個不相干的root對象時,使用 #root[n]. 進行訪問,
n是root對象當前在棧中的順序。從0開始。

請看下面的例子:

Java代碼  收藏代碼
  1. public class UserAction {  
  2.   
  3.     private String username;  
  4.   
  5.     //查看用戶的詳細信息  
  6.     public String detail(){  
  7.   
  8.        username = "張三";        
  9.   
  10.        List list = new ArrayList();  
  11.        for(int i=0; i<10; i++){  
  12.            User user = new User();  
  13.            user.setUsername("User"+i);  
  14.            list.add(user);  
  15.        }  
  16.   
  17.        ActionContext.getContext().put("users", list);        
  18.   
  19.        User u = new User();  
  20.        u.setUsername("趙毅");  
  21.        ActionContext.getContext().getValueStack().push(u);        
  22.   
  23.        return "detail";  
  24.     }  
  25.    


對應的JSP如下:

Java代碼  收藏代碼
  1.   <s:property value="username"/> <br/>  
  2.   <s:iterator value="#users">  
  3.      <s:property value="username"/>  
  4.      <s:property value="#root[2].username"/><br/>  
  5.   </s:iterator>  
  6.   <s:property value="username"/>  
  7.   <s:property value="#root[1].username"/> <!-- 張三 -->  


根據剛纔的示例,我們知道,第1行的username是“趙毅”(因爲JSP在執行這行代碼的時候,CompoundRoot中有兩個元素:第0個是“user對象趙毅”,第1個是“userAction對象張三”),因此第1行的username將取出CompoundRoot中第0個元素的username屬性:趙毅

第2行代碼是iterator標籤,只定義了一個value屬性,iterator標籤將循環訪問users這個List中的User對象,並把當前循環的user對象壓入到CompoundRoot中!所以,在第3行和第4行代碼被執行的時候,CompoundRoot中總共有3個元素:第0個元素是被iterator標籤壓入的當前循環的user對象;第1個元素是“user對象趙毅”;第2個元素是“userAction對象張三”,因此第3行代碼的執行結果就是輸出“UserX”,即當前循環的user對象的username屬性!iterator標籤將會依次取出List中的user對象,並不斷壓入/彈出user對象(每次循環,都將執行一遍壓入/彈出)。而第4行代碼取第2個元素的username屬性,即userAction對象的username屬性:張三。

第5行代碼執行完成之後,在CompoundRoot中將剩下2個元素,與第2行代碼被執行之前一樣。所以,第6行代碼的輸出和第1行代碼的輸出結果是一樣的,而第7行代碼將取出userAction對象的username屬性:張三

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章