《Spring in Action》筆記第六彈,深入 Spring MVC 豐富的控制器繼承體系、命令對象綁定、驗證框架整合,並給出對 Spring MVC 設計複雜度的客觀評價。
Controller (介面)
├─ AbstractController // 基礎:handleRequestInternal(req, res) → ModelAndView
├─ AbstractCommandController // 命令對象:handle(req, res, cmd, errors)
│ └─ AbstractFormController // 表單流程:formView/successView, GET顯示/POST處理
│ ├─ SimpleFormController // 簡易表單:doSubmitAction(cmd) / onSubmit(cmd)
│ └─ AbstractWizardFormController // 向導式表單(多步驟)
├─ MultiActionController // 多動作:methodNameResolver 導向同 Controller 不同方法
└─ ThrowawayController // 原型作用域(見上篇)
Struts/WebWork Action 體系較扁平,Spring MVC 提供細粒度繼承,針對不同場景預設流程,但也增加學習曲線。
AbstractCommandController 要求設定 commandClass(POJO),Spring 自動將請求參數綁定至命令對象屬性(支援巢狀屬性)。控制器覆寫:
protected ModelAndView handle(HttpServletRequest req, HttpServletResponse res,
Object command, BindException errors) {
MyCommand cmd = (MyCommand) command;
// 業務邏輯
return new ModelAndView("successView", "result", result);
}
配置檔可注入命令類別名稱(PropertyEditor 自動轉 Class):
<property name="commandClass" value="com.example.MyCommand"/>
formView。formView 攜帶錯誤 → 成功 onSubmit() → successView。public class UserValidator implements Validator {
public boolean supports(Class clazz) { return User.class.equals(clazz); }
public void validate(Object target, Errors errors) {
User u = (User) target;
ValidationUtils.rejectIfEmpty(errors, "username", "required.username", "用戶名必填");
if (!EMAIL_PATTERN.matcher(u.getEmail()).matches())
errors.rejectValue("email", "invalid.email", "郵箱格式錯誤");
}
}
注入控制器:
<property name="validator">
<bean class="com.example.UserValidator"/>
</property>
validate() 在 handleRequestInternal 前自動調用;SimpleFormController.onSubmit() 執行後將 errors 傳給視圖(JSP 可用 <form:errors path="*"/> 顯示)。
StudentValidator 定義 validatePhone()/validateEmail() 但 validate() 未調用。ModelAndView 僅支援單一模型屬性(第二、三參數),多屬性仍需 request.setAttribute() 或回傳 Map(Spring 2.0+ 支援)。| 優點 | 缺點 |
|---|---|
| 與 IoC 容器無縫整合,依賴注入極自然 | 控制器繼承體系過深,切換基類需改方法簽名,維護成本高 |
| 驗證邏輯與領域對象分離,符合關注點分離 | HandlerMapping 多種並存(BeanName/SimpleUrl/CommonsPath),URL 導向不透明 |
| 攔截器機制靈活(HandlerInterceptor) | 表單驗證僅支援代碼式,缺乏聲明式/配置式驗證(Struts/WebWork 強項) |
| 視圖解析器可插拔,支援多種模板引擎 | ModelAndView 早期版本模型承載能力弱 |
Spring 2.5+ 引入 @Controller/@RequestMapping/@ModelAttribute/@Valid 註解式編程,徹底取代繼承體系,解決上述多數痛點。舊專案維護時理解繼承體系有助於閱讀舊代碼;新專案**請直接使用註解式 Spring MVC**。