在 Struts2 應用開發中,Action 鏈 是實現「伺服端轉發」並共享請求資料的核心機制。alias 攔截器專門解決「來源 Action 欄位名稱與目標 Action 欄位名稱不一致」的參數映射問題。本文詳細解析其配置原理、實戰用法與常見陷阱。
| 特性 | Chain Result (type="chain") | Redirect Action (type="redirectAction") |
|---|---|---|
| 轉發位置 | 伺服端 (同一請求) | 客戶端 (HTTP 302 新請求) |
| 請求物件 | 共享同一 HttpServletRequest | 新請求,原請求屬性丟失 |
| 參數傳遞 | 自動攜帶所有請求參數 + ValueStack | 需顯式 <param> 或 Session |
| URL 變化 | 瀏覽器網址列**不變** | 瀏覽器網址列**更新**為目標 Action |
| 適用場景 | 多步驟表單、工作流、權限檢查後轉發 | POST-Redirect-GET 模式、防止重複提交 |
當使用 Chain Result 時,目標 Action 透過 alias 攔截器接收參數。其核心功能:將來源參數名稱按映射規則重新命名,注入目標 Action 的對應屬性。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<package name="default" extends="struts-default">
<!-- 來源 Action -->
<action name="submitOrder" class="com.example.order.SubmitOrderAction">
<result name="success">/confirm.jsp</result>
<result name="input" type="chain">
<param name="actionName">processPayment</param>
</result>
</action>
<!-- 目標 Action:使用 alias 攔截器映射參數 -->
<action name="processPayment" class="com.example.order.ProcessPaymentAction">
<!-- 關鍵配置:aliases 參數定義名稱映射 -->
<param name="aliases">#{'orderId':'paymentOrderId', 'customerName':'payerName', 'amount':'payAmount'}</param>
<result name="success">/paymentResult.jsp</result>
<result name="input">/paymentForm.jsp</result>
</action>
</package>
package com.example.order;
public class SubmitOrderAction extends ActionSupport {
private String orderId;
private String customerName;
private BigDecimal amount;
// getter/setter 省略
public String execute() {
// 業務邏輯驗證
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
addFieldError("amount", "金額必須大於零");
return INPUT; // 觸發 chain 到 processPayment
}
return SUCCESS;
}
}
package com.example.order;
public class ProcessPaymentAction extends ActionSupport {
// 屬性名稱與 aliases 映射的目標名稱一致
private String paymentOrderId;
private String payerName;
private BigDecimal payAmount;
// getter/setter **必須存在**,否則無法注入
public String execute() {
// 此時 paymentOrderId、payerName、payAmount 已自動注入
// 呼叫支付閘道...
return SUCCESS;
}
}
<param name="aliases">#{'sourceParam1':'targetProp1', 'sourceParam2':'targetProp2'}</param>
#{ '來源參數名' : '目標屬性名', ... } (OGNL Map 語法)
用戶提交表單 → SubmitOrderAction.execute() → 返回 "input"
↓
ChainResult 執行
↓
目標 Action (processPayment) 被調用
↓
AliasInterceptor.intercept() 執行
↓
遍歷 aliases Map:
從 ValueStack/請求獲取 sourceParam 值
呼叫 targetAction.setTargetProp(value)
↓
目標 Action.execute() 執行 (屬性已注入)
| 限制/陷阱 | 說明 | 對策 |
|---|---|---|
| 目標屬性**必須有 setter** | Ognl 需呼叫 setXxx() 注入值 | 確保所有映射目標屬性提供 public setter |
| 來源參數**必須在 ValueStack 或請求中** | Chain Result 會將來源 Action 實例壓入 ValueStack | 來源 Action 屬性需有 getter,或手動 request.setAttribute() |
| 類型轉換自動進行 | Struts2 類型轉換器處理 String → 目標類型 | 複雜類型註冊自定義 TypeConverter |
| 避免循環鏈 | A→B→A 導致無限遞迴 | 設計單向流程,或用 redirectAction 打破 |
| Chain Result 不改變 URL | 用戶重新整理會重送原請求 | 適合「單次提交、多步處理」;不適合「結果頁」 |
<!-- 支援 OGNL 運算式動態決定映射 -->
<param name="aliases">#{'user_*': 'profile_*'}</param>
<!-- 注:Struts2 核心 alias 攔截器不直接支援通配符,需擴展 AliasInterceptor 或使用 ActionMapper -->
session.put("key", val) → 耦合 Session、併發風險、需手動清理<param name="orderId">%{orderId}</param> → URL 暴露參數、長度限制、GET 語義ActionContext.getContext().getValueStack().findValue("orderId") → 程式碼耦合框架內部alias 攔截器是 Struts2 「伺服端轉發 + 參數重命名」的標準解決方案。掌握 Chain Result、ValueStack、JavaBean 慣例 三者交互機制,能優雅實現多步驟業務流程、權限攔截轉發、表單預填等場景。現代專案若遷移至 Spring MVC,對應機制為 @ModelAttribute + forward: 前綴或 HandlerInterceptor 手動映射。