版權聲明:本文爲 小異常 原創文章,非商用自由轉載-保持署名-註明出處,謝謝!
本文網址:https://blog.csdn.net/sun8112133/article/details/106677519
文章目錄
值棧(ValueStack) 在 Struts2 中也是非常重要的知識,它其實類似於一個數據中轉站,Struts2 框架中的所有數據都保存到了 ValueStack 中。ValueStack 貫穿整個 Action 的生命週期,只要 Action 一創建,Struts2 就會創建一個 ValueStack 對象。
ValueStack 的實現類是 OgnlValueStack 對象,這個對象實現了 ValueStack 接口。
大家需要記住在 ValueStack 中存入的數據在任何地方都能把它取出來。
一、值棧的內部結構
ValueStack 的內部主要有兩個區域:root 區域 和 context 區域。
- root 區域: 其實就是一個 ArrayList。裏面一般放置對象。獲取 root 的數據不需要加
#
; - context 區域: 其實就是一個 Map。裏面放置是 web 開發常用的對象數據引用。獲取 context 數據需要加
#
。
我們一般所說的操作 ValueStack,通常指的是操作 ValueStack 中的 root 區域。
二、值棧與 ActionContext 的關係
說起 ActionContext,大家肯定會想到 Servlet 中的 ServletContext。
ServletContext 是 Servlet 的上下文。所謂的上下文其實就是它包含了全部,和上知五百年下知五百年道理一樣,包含了全部信息;
而 ActionContext 是 Action 的上下文。通過源碼得知:當請求過來的時候,執行過濾器中的 doFilter 方法,在這個方法中創建 ActionContext 對象,在創建 ActionContext 的過程中,就會創建 ValueStack 對象,並將 ValueStack 對象傳遞給 ActionContext 對象。所以我們 可以通過 ActionContext 獲取 ValueStack 對象 了。
ActionContext 對象之所以能夠訪問 Servlet 的 API (訪問的是域對象的數據)。因爲在其內部有值棧的引用。
三、操作值棧
1、獲得值棧
獲得 值棧 有兩種方式:
- 通過 ActionContext 對象獲取 值棧;
- 通過 Request 對象獲取 值棧。在 Struts2 的內部,已經將 值棧 存入到了 Request 中。
@Override
public String execute() throws Exception {
// 一種:通過 ActionContext 對象獲得
ValueStack valueStack1 = ActionContext.getContext().getValueStack();
// 二種:通過 request 對象獲得 "struts.valueStack"
ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
// 一個 Action 的實例,只會創建一個 ValueStack 的對象
System.out.println(valueStack1 == valueStack2); // true
return NONE;
}
2、向值棧中存入數據
向 值棧 中存入數據有兩種方式:
- 在 Action 中提供屬性的 get 方法;
- 使用 ValueStack 中本身的方法(推薦)。
1)在 Action 中提供屬性的 get 方法
默認情況下,將 Action 對象放入到值棧中,而 Action 中的屬性也會存入,但是我們不推薦使用這種方式,因爲它存入的數據不在棧頂。
-
編寫 JSP
<body> <h1>查看值棧的內部結構</h1> <s:debug></s:debug> <!-- 利用 Action 在值棧中的特性 --> <s:property value="user.username" /> <s:property value="user.password" /> </body>
-
編寫 Action 類
/** * 操作 ValueStack * 方式一:利用 Action 本身在值棧中的特性。 */ public class ValueStackDemo3 extends ActionSupport { private User user; public User getUser() { return user; } @Override public String execute() throws Exception { // 向 ValueStack 中存值 user = new User("張三", "222"); return SUCCESS; } }
2)使用 ValueStack 中本身的方法(推薦)
-
編寫 JSP
<body> <h1>查看值棧的內部結構</h1> <s:debug></s:debug> <!-- 調用 ValueStack 本身的方法,如果有兩個相同名字的,優先棧頂的 --> <s:property value="username" /> <s:property value="password" /> </body>
-
編寫 Action 類
/** * 操作 ValueStack * 方式二:調用值棧中的方法實現 */ public class ValueStackDemo4 extends ActionSupport { @Override public String execute() throws Exception { // 向值棧中保存數據 // 獲得值棧對象 ValueStack valueStack = ActionContext.getContext().getValueStack(); // 使用 push(Object obj); set(String key, Object obj); // 一般保存對象用 push,保存集合用 set User user = new User("李四", "333"); // 現在 user 在棧頂的位置 valueStack.push(user); valueStack.set("name", "王五"); // 創建一個 Map 集合,將 Map 壓入到棧中 return SUCCESS; } }
3、獲取值棧數據
獲取值棧中的數據就是在頁面中使用 OGNL 表達式即可。
- 獲取 root 的數據時不需要加
#
號; - 獲取 context 數據需要加
#
號。
<body>
<h3>獲取 root 的數據</h3>
<s:property value="username" />
<h3>獲取 context 的數據</h3>
<s:property value="#name" />
</body>
4、EL 爲何能訪問到值棧的數據
因爲 Struts2 框架的底層對
request.getAttribute(String name);
進行了增強,首先從 request 中獲取值,如果找到了就返回,如果沒找到就從值棧中獲取。