首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Struts2 OGNL 與 ValueStack 核心機制圖解:根對象、Context Map 與 # 前綴規則

     編輯:Java 綜合教學

OGNL 簡介

Object-Graph Navigation Language:開源表達式語言,通過統一語法訪問對象圖屬性、調用方法、遍歷集合、類型轉換。Struts2 將 OGNL 作為默認表達式引擎,視圖層標簽 (<s:property>、<s:if> 等) 底層均靠 OGNL 求值。

OGNL 上下文結構

OGNL 上下文本質是 Map<String, Object> (實現類 OgnlContext),包含:

  • 一個根對象:context.getRoot(),直接訪問無需前綴。
  • 多個命名對象:以 key-value 存放,訪問需 #key.property。

Struts2 將 ActionContext 設置為 OGNL 上下文,並把 ValueStack 設置為根對象。

ValueStack 結構可視化( 效果)

ValueStack (Root Object - ArrayList 模擬棧)
├── [0] User{username='張三', age=25}     ← 棧底
├── [1] Order{id=1001, amount=99.9}      ← 棧頂
└── ...

Stack Context (Map)
├── "request"     → {msg="登錄成功"}
├── "session"     → {user=User@123}
├── "application" → {config=...}
├── "parameters"  → {username="張三", password="***"}
└── "attr"        → 合併請求/會話/應用屬性

Action 向上下文放值的兩種方式對比

方式代碼存放位置頁面取值適用場景
單列 (推薦)vs.push(user);ValueStack root 列表<s:property value="username"/>領域模型、表單回顯、列表迭代
雙列vs.getContext().put("msg", "成功");Stack Context Map<s:property value="#msg"/>臨時消息、標志位、非領域數據

虛擬對象查找機制(Struts2 核心增強)

OGNL 原生只支持一個根對象。Struts2 實現 OgnlValueStack 繼承 ArrayList 並實現 ValueStack 接口,內部持有 CompoundPropertyAccessor:

  1. 表達式求值時,從 棧頂 (index=size-1) 向棧底 (index=0) 遍歷。
  2. 對每個元素嘗試獲取屬性,首個成功返回(非 null 或屬性存在)。
  3. 若所有元素均無該屬性,拋出 NoSuchPropertyException。

這意味著:棧頂對象同名屬性會遮蓋棧底對象,頁面無需關心對象在棧中深度。

頁面訪問語法速查表

<!-- 1. ValueStack root 屬性 (直接) -->
<s:property value="username"/>
<s:property value="order.id"/>

<!-- 2. Stack Context / ActionContext Map (需 #) -->
<s:property value="#request.msg"/>
<s:property value="#session.user.username"/>
<s:property value="#parameters.id"/>
<s:property value="#attr.config"/> <!-- 跨域搜尋 -->

<!-- 3. OGNL 內置對象 -->
<s:property value="#request"/> <!-- 整個 Map -->
<s:property value="#session.id"/>

<!-- 4. 集合操作 -->
<s:iterator value="orderList"> <s:property value="id"/> </s:iterator>
<s:property value="orderList[0].id"/>
<s:property value="userMap['key'].name"/>

最佳實踐與避坑

  1. 優先單列:代碼 vs.push(model),頁面無 #,可讀性最高。
  2. ModelDriven 自動裝配:Action 實現 ModelDriven<T>,getModel() 返回模型,攔截器自動 push,零代碼侵入。
  3. 同名屬性遮蓋:棧中多對象有同名字段時,棧頂勝出。需精確控制時用 #[1].field (索引從 0 起,棧底為 0)。
  4. 不要濫用雙列放領域對象:會導致頁面到處加 #,且無法享受虛擬對象查找便利。
  5. 開發必開:實時觀察 root/context 變量,排查取值失效首選工具。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved