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

Struts2 同一 Action 處理多 Model 請求:ParameterAware 實作詳解

     編輯:Java 相關知識

問題情境

專案整合第三方支付(易寶)時,PayAction 需同時處理兩種請求:

  1. 發起支付:前端送出訂單資料(SendData 模型)
  2. 接收回調:易寶回傳支付結果(BackData 模型)

但 Struts2 ModelDriven<T> 僅支援單一 Model,若強行繼承共同父類,違反單一職責且模型無實質關聯。

解決方案:實作 ParameterAware 手動綁定

Struts2 ParameterAware 介面提供 setParameters(Map<String, String[]>),可在攔截器鏈中 ServletConfigInterceptor(早於 ModelDrivenInterceptor)注入完整請求參數 Map。利用此特性,在 getModel() 中依參數特徵動態決定回傳哪個 Model 實例。

程式碼實作

1. Action 實作 ParameterAware

@Controller("payAction")
@Scope("prototype")
public class PayAction extends BaseAction<Object> implements ParameterAware {

    private Map<String, String[]> parameters;

    @Override
    public void setParameters(Map<String, String[]> parameters) {
        this.parameters = parameters;
    }

    @Override
    public Object getModel() {
        // 易寶發起支付時會帶 pd_FrpId(銀行代碼),回調則無
        if (parameters != null && parameters.containsKey("pd_FrpId")) {
            model = new SendData();   // 發起支付模型
        } else {
            model = new BackData();   // 接收回調模型
        }
        return model;
    }

    // 發起支付
    public String goBank() {
        SendData sendData = (SendData) model;
        // 組裝表單、簽名、導向易寶...
        return "goBank";
    }

    // 接收回調
    public void backBank() {
        BackData backData = (BackData) model;
        // 驗簽、更新訂單狀態、發送通知...
    }
}

2. 為何可行?Struts2 執行順序

1. 建立 Action 實例
2. 執行攔截器鏈(依 struts-default.xml 順序)
   ├─ ServletConfigInterceptor → 注入 parameters Map
   ├─ ModelDrivenInterceptor   → 呼叫 getModel()
   └─ ...其他攔截器
3. 呼叫 Action 方法
4. 反向執行攔截器鏈

因 ServletConfigInterceptor 在 ModelDrivenInterceptor 之前,故 getModel() 時 parameters 已就緒,可安全判斷。

3. 回調處理邏輯補充

public void backBank() {
    BackData backData = (BackData) model;
    boolean verified = payService.verifyCallback(backData);

    if (verified) {
        // 1. 更新訂單狀態(易寶回傳訂單號在 r6_Order)
        String orderId = backData.getR6_Order();
        forderService.updateStatusById(Integer.parseInt(orderId), 2); // 2=已付款

        // 2. 發送 Email、簡訊通知(r8_MP 格式:email,phone)
        String[] mp = backData.getR8_MP().split(",");
        emailUtil.sendEmail(mp[0], orderId);
        messageUtil.sendSms(mp[1], orderId);
    }
}

關鍵優勢

  • 模型解耦:SendData、BackData 互不相干,各司其職
  • 零配置:無需修改 struts.xml 增加 result 或 action
  • 擴充性:未來新增第三種請求(如退款回調),只需在 getModel() 增加判斷分支

注意事項

  • 判斷依據(如 pd_FrpId)必須是兩類請求「絕對互斥」的特徵參數
  • BaseAction 泛型需改為 Object,避免類型衝突
  • 若專案已大量使用 ModelDriven,建議統一規範:單一 Model 用 ModelDriven,多 Model 用 ParameterAware

小結

透過 ParameterAware 搭配 Struts2 攔截器執行順序,優雅解決單一 Action 處理多種 Model 請求的問題,避免強行繼承或拆分 Action 導致的代碼碎片化,是整合第三方回調介面的實用模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved