ActionContext (ThreadLocal, 每請求一個) ├── ValueStack (OgnlValueStack) ← OGNL 根對象 (Root) │ ├── [Object1, Object2, ...] ← 單列棧結構,後進先出 │ └── 虛擬對象查找機制 ├── Stack Context (Map) ← 雙列結構,需 # 前綴訪問 │ ├── request (Map) │ ├── session (Map) │ ├── application (Map) │ ├── parameters (Map) │ └── attr (Map) └── 其他:action, parameters 等
// Action 中 ValueStack vs = ServletActionContext.getContext().getValueStack(); // 或從 request 取 ValueStack vs = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
ArrayList<Object>,模擬棧,push() 入棧,pop() 出棧,peek() 取棧頂。OgnlContext,包含上述 Stack Context 等 Map。| 方式 | 代碼 | 存放位置 | 頁面取值語法 |
|---|---|---|---|
| 單列 (推薦) | vs.getRoot().push(user); 或 vs.push(user) | ValueStack root 列表 | <s:property value="username"/> (直接屬性名) |
| 雙列 | vs.getContext().put("user", user); | Stack Context Map | <s:property value="#user.username"/> (需 # 前綴) |
OGNL 原生上下文只有一個根對象。Struts2 的 OgnlValueStack 實現了特殊的 PropertyAccessor:按棧頂→棧底順序遍歷 root 列表,首個擁有該屬性的對象「勝出」。因此頁面可直接寫屬性名,無需關心對象在棧中位置。
ThreadLocal<ActionContext>,請求級隔離。ActionContext.getContext() 獲取當前上下文。ValueStack、request/session/application Map、parameters、attr (搜尋順序 request→session→application) 等。<s:debug></s:debug> <!-- 頁面右下角浮動圖標,點擊彈窗顯示 --> <!-- Value Stack Contents (root 列表) --> <!-- Stack Context (context Map) -->
利用它實時觀察值棧/上下文變量變化,排查「為什麼取不到值」極其高效。
username,支持鏈式 user.address.city。#request.msg、#session.user、#parameters.id。#request、#session、#application、#parameters、#attr、#vs (值棧自身)。list[0]、map.key、list.{? #this.age>18} (投影)、list.{^ #this.age>18} (首個匹配)。vs.push(obj),頁面取值簡潔,符合 Struts2 設計初衷。public Object getModel() { return model; },框架自動將 model push 到值棧頂,省去手動 push。#[index].property 指定位置(如 #[1].username 取第二個對象)。vs.clear(),防止內存洩漏。