Object-Graph Navigation Language:開源表達式語言,通過統一語法訪問對象圖屬性、調用方法、遍歷集合、類型轉換。Struts2 將 OGNL 作為默認表達式引擎,視圖層標簽 (<s:property>、<s:if> 等) 底層均靠 OGNL 求值。
OGNL 上下文本質是 Map<String, Object> (實現類 OgnlContext),包含:
context.getRoot(),直接訪問無需前綴。#key.property。Struts2 將 ActionContext 設置為 OGNL 上下文,並把 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" → 合併請求/會話/應用屬性
| 方式 | 代碼 | 存放位置 | 頁面取值 | 適用場景 |
|---|---|---|---|---|
| 單列 (推薦) | vs.push(user); | ValueStack root 列表 | <s:property value="username"/> | 領域模型、表單回顯、列表迭代 |
| 雙列 | vs.getContext().put("msg", "成功"); | Stack Context Map | <s:property value="#msg"/> | 臨時消息、標志位、非領域數據 |
OGNL 原生只支持一個根對象。Struts2 實現 OgnlValueStack 繼承 ArrayList 並實現 ValueStack 接口,內部持有 CompoundPropertyAccessor:
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"/>
vs.push(model),頁面無 #,可讀性最高。ModelDriven<T>,getModel() 返回模型,攔截器自動 push,零代碼侵入。#[1].field (索引從 0 起,棧底為 0)。