A.值棧概述 值棧(ValueStack),通俗的來說就是Struts2裡面用來管理和存儲數據的東西。struts2項目部署運行後,底層會創建一個action實例,同時也會在記憶體上劃分一塊區域,這個區域就是值棧,該值棧對象會貫穿整個Action生命周期,用來存儲這個過程中的數據。 B.值棧結構 首先 ...
A.值棧概述
值棧(ValueStack),通俗的來說就是Struts2裡面用來管理和存儲數據的東西。struts2項目部署運行後,底層會創建一個action實例,同時也會在記憶體上劃分一塊區域,這個區域就是值棧,該值棧對象會貫穿整個Action生命周期,用來存儲這個過程中的數據。
B.值棧結構
首先,我們一起去看看struts2中值棧在哪裡。找到xwork-core--->com.opensymphony.xwork2.util------>ValueStack
這個ValueStack是介面,裡面沒有具體功能實現,並不能拿來直接用,查看它的實現類,發現是OgnlValueStack,也就是說,真正起作用的,底層創建的實例是該實現類。值棧中有兩個主要區域:
1.root區域.
點進去看看這個root到底是什麼?
public class CompoundRoot extends ArrayList //原來root其實就是一個ArrayList集合,只不過裡面添加了出棧和進棧的方法,也就是說它變成棧了,不過還是遵循list集合
CompoundRoot:存儲了Action的實例,是ognl的root對象,struts2對原先ognl的root對象改進,使用CompoundRoot自定義棧(擴展了ognl),它讀取Action屬性值時會先從棧頂對象中找對應的屬性,找不到繼續找棧中其他對象,找到則停止。
2.context區域
(註: transient是聲明對象不允許被序列化) 這裡context其實是OgnlContext的上下文。它是一個map結構,裡面存放了一些引用。
parameters:該Map中包含當前請求的請求參數。
request::該Map中包含當request對象中的所有屬性。
session:該Map中包含當session對象中的所有屬性
application:該Map中包含當application對象中的所有屬性
attr:該Map按照如下順序來檢索某一個屬性:request,session,application.
3.ActionContext和ValueStack的關係
通過查看源碼可以知道,在ActionContext創建時,也會創建一個ValueStack對象,並且將該對象給ActionContext。即ActionContext裡面有一個valueStack引用,而ValueStack裡面也有ActionContext的應用。這一點,我們可以通過利用ActionContext獲取Servlet原生API的方式就可以看出。主要就是獲取值棧裡面的Servlet對象。
C.值棧的使用。
1.獲取值棧對象。(同一個Action中獲取到的值棧是同一個)
---通過ActionContext對象來獲取值棧
// 通過ActionContext對象來獲取ValueStack對象(其實是一個父類引用指向子類方法) ValueStack stack1 = ActionContext.getContext().getValueStack();
---通過request對象來獲取
ValueStack stack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
2.操作值棧
一般操作值棧都是指操作root區域。
- 在Action中提供屬性的get方法方式。(這裡直接演示表單提交方式,簡單類型和對象類型)
action類中
private User user; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String useStack() { System.out.println(user.getName()); return SUCCESS; }
jsp頁面
從值棧裡面取出值:
<s:property value="user.name"/>-----------------<s:property value="password"/>
<s:debug></s:debug>
運行結果
通過上述可以知道,預設情況下,會將Action對象壓入到值棧中,所以其中的屬性也在值棧中。在jsp頁面顯示時直接寫屬性名,如果是對象,由於用get方法對象不一定在棧頂,所以要用對象名.屬性名。屬性不要重覆
- 手動操作值棧(註意被壓入棧中的都是對象,你傳什麼類型,底層會被封裝成對象,可以自已push對象和普通屬性,看看root區)
action頁面
public String handUseStack() { ValueStack stack = ActionContext.getContext().getValueStack(); stack.push(user); //只是用來保存對象,將對象壓入到棧中,傳普通屬性底層會包裝成類對象 stack.set("password", password); //只要用set方法,底層會創建一個map集合,但是你看不到裡面的屬性和屬性值。這是因為這個map集合沒有set和get方法,不過沒關係,雖然顯示空,但是可以取出來。
return SUCCESS; }
jsp頁面(與將Action自動壓入棧時取對象值有區別,只需要使用屬性名就可以取)
dy>
從值棧裡面取出值:
<s:property value="name"/>-----------------<s:property value="password"/>
<s:debug></s:debug>
運行結果:
3.操作Context區域
由於context區域裡面封裝了域對象,所以直接利用域對象就可以達到我們操作context的目的
action頁面
public String useContext() { // 利用Action中內置對象獲取request對象,向域中存值。其他的域都是一樣 ServletActionContext.getRequest().setAttribute("user", user); ServletActionContext.getRequest().setAttribute("password", password); return SUCCESS; }
jsp頁面(取值還是和上面root區一樣,只不過要加上一個#聲明)
從context裡面取出值:
<s:property value="#request.user.name"/>+..........+<s:property value="#request.password"/>
<s:debug></s:debug>
運行結果
如上圖所示,都存到了contex區域裡面了,普通屬性直接屬性名,如password,對象就直接用對象.屬性 如 user.name.