Struts2動態方法調用(DMI)配合通配符映射時,極易出現「一個請求匹配多個Action」的隱蔽bug。本文通過實戰案例深度剖析struts.xml映射規則優先級、通配符捕獲機制,提供徹底解決方案。
$http({
method: "POST",
url: "/AzraelShop/Mgr-getAllUsers", // 目標:getAllUsersAction
data: {}
})
<package name="mgr" namespace="/Mgr" extends="struts-default">
<!-- 配置1:精確匹配 Mgr-*User -->
<action name="Mgr-*User" class="com.azrael.controller.MgrController" method="{1}UserAction">
<result type="json">
<param name="includeProperties">user.*</param>
</result>
</action>
<!-- 配置2:通用通配符 *-* -->
<action name="*-*" class="com.azrael.controller.{1}Controller" method="{2}Action">
<result type="json"/>
</action>
</package>
請求/Mgr-getAllUsers同時觸發:
MgrController.getAllUsersAction()(預期)MgrController.getUserAction()(非預期,因getAllUsers匹配{1}=getAll, {2}=Users)struts.xml中<action>定義順序決定嘗試順序*-*能匹配任意包含連字符的字符串method="{2}Action"將第二個通配符組作為方法名後綴請求路徑:/Mgr-getAllUsers
配置1:name="Mgr-*User"
模式:Mgr- + [任意字符] + User
匹配:getAllUsers 以 User 結尾?否 → 匹配失敗
配置2:name="*-*"
模式:[任意字符] + - + [任意字符]
分組:{1}="Mgr", {2}="getAllUsers"
映射:class="MgrController", method="getAllUsersAction"
→ 匹配成功,執行 getAllUsersAction()
但同時:{2}="getAllUsers" 也被 DML 解析為方法名
Struts2 內部邏輯嘗試調用 getUserAction()(getter 慣例)
Struts2約定:getXxx()方法會被識別為屬性獲取器。當{2}以get開頭時:
getAllUsers → 嘗試調用getAllUsersAction()(正確)get前綴 → 嘗試調用getUserAction()(錯誤,將AllUsers視為屬性名)<package name="mgr" namespace="/Mgr" extends="struts-default">
<!-- 1. 精確業務映射優先 -->
<action name="getAllUsers" class="com.azrael.controller.MgrController" method="getAllUsersAction">
<result type="json"><param name="includeProperties">user.*</param></result>
</action>
<action name="getUser" class="com.azrael.controller.MgrController" method="getUserAction">
<result type="json"/>
</action>
<!-- 2. 通用落後兜底,限制模式 -->
<action name="*-*" class="com.azrael.controller.{1}Controller" method="{2}Action">
<result type="json"/>
<!-- 可添加 excludeMethods 防止誤觸 -->
</action>
</package>
// MgrController.java
@Namespace("/Mgr")
@Action(value="getAllUsers", results={@Result(type="json", params={"includeProperties","user.*"})})
public String getAllUsersAction() { ... }
@Action(value="getUser", results={@Result(type="json")})
public String getUserAction() { ... }
在struts.xml中僅保留<package>掃描配置,避免通配符衝突。
<constant name="struts.action.excludeMethods" value="get*,set*,is*" />
在struts.properties或<constant>中配置,禁止get開頭的方法被DMI調用。
get/set/is開頭,改用load/find/query/donamespacestruts.mapper.alwaysSelectFullNamespace=trueStruts2通配符映射雖便捷,但「隱式行為」是生產事故高發區。顯式配置雖繁瑣,卻是系統穩定性的基石。