Struts2 作為經典 MVC 框架,其 Action 作為「業務控制器」承擔參數接收、業務調度、結果導向三大職責。本文深度講解屬性驅動、模型驅動、JavaBean三種參數接收模式的適用場景與代碼實現,並演示動態方法調用與通配符映射如何大幅簡化 struts.xml 配置量。
StrutsPrepareAndExecuteFilter,攔截所有請求,委派給 Action
// Action
public class UserAction extends ActionSupport {
private String username;
private String password;
// 必須提供 setter,框架調用 setXxx()
public void setUsername(String username) { this.username = username; }
public void setPassword(String password) { this.password = password; }
public String login() {
// 直接使用 username, password
return SUCCESS;
}
}
<!-- login.jsp -->
<form action="login" method="post">
用戶名: <input name="username" /> <!-- name 與 Action 屬性名一致 -->
密碼: <input name="password" />
<input type="submit" />
</form>
優點:簡單直觀;缺點:Action 膨脹、參數多時維護困難、無法直接接收復雜對象。
// 實體類
public class User {
private String username;
private String password;
// getter/setter...
}
// Action
public class UserAction extends ActionSupport {
private User user; // 封裝參數
public void setUser(User user) { this.user = user; }
public User getUser() { return user; }
public String execute() { ... }
}
<!-- JSP 字段名加前綴 -->
<input name="user.username" />
<input name="user.password" />
優點:參數對象化、便於傳遞給 Service;缺點:JSP 字段名冗長。
public class UserAction implements ModelDriven {
private User user = new User(); // 必須實例化
@Override
public User getModel() { return user; } // 返回棧頂模型
public String execute() {
// 直接 user.getUsername(),或 Service 直接用 user
return SUCCESS;
}
}
<!-- JSP 字段名無前綴 -->
<input name="username" />
<input name="password" />
原理:Struts2 通過 ModelDrivenInterceptor 調用 getModel() 將返回對象壓入 ValueStack 棧頂,OGNL 表達式直接解析到模型屬性。
<action name="login" class="action.UserAction" method="login">
<result name="input">login.jsp</result>
<result>welcome.jsp</result>
</action>
<action name="all" class="action.DeptAction" method="getDept">
<result>list.jsp</result>
</action>
一個 Action 類可配置多個 <action>,各自指定不同 method,實現「一類多入口」。
<action name="user" class="action.UserAction"> <!-- 無 method -->
<result>list.jsp</result>
</action>
<form action="user!save" method="post"> <!-- 格式:actionName!methodName -->
...
</form>
風險:暴露內部方法名、繞過攔截器棧、安全審計困難。禁用方式:
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<action name="user_*" class="action.UserAction" method="{1}">
<result>{1}.jsp</result> <!-- {1} 為通配符捕獲的內容 -->
</action>
user_add → 調用 add() → 返回 add.jsp
user_delete → 調用 delete() → 返回 delete.jsp
<action name="user_add" class="action.UserAction" method="add"> <!-- 精確匹配優先 -->
<result>add.jsp</result>
</action>
<action name="user_*" class="action.UserAction" method="{1}"> <!-- 通配符次之 -->
<result>{1}.jsp</result>
</action>
匹配順序:
<action name="*/user/*" class="action.{1}UserAction" method="{2}">
<result>/{1}/user/{2}.jsp</result>
</action>
admin/user/save → 類 action.AdminUserAction、方法 save()、視圖 /admin/user/save.jsp
user.address.city 自動級聯賦值struts.enable.DynamicMethodInvocation=falseuser_* 覆蓋增刪改查,配置量減少 80%<package namespace="/admin"> 避免 action 名稱衝突掌握這些進階技巧,能讓 Struts2 專案從「配置地獄」進化為「約定優於配置」的輕量級 MVC 架構,專注於業務邏輯而非 XML 搬運。