81. Spring 提供了豐富的控制器層次,方便根據實際需求選擇實現或繼承那一種控制器。不像 Struts 和 WebWork 比較平坦的 Action 層次。比如 ThowawayController/MultiActionController/SimpleFormController 等。 (P254)
82. 繼承 AbstractController 要覆蓋的方法是 handleRequestInternal(request,response);new ModelAndView("counrseList","courses",courses) 第一個參數是 view 的邏輯名,第二第三個參數是傳 遞給 view 的名稱/數值對,那要向 View 傳遞多個參數就還是要用 request.setAttribute() 了。 (P256)
83. 當控制器需要根據參數執行工作時,如參數綁定到業務對象,插入驗證器的鉤子,應該繼承 AbstractCommandController,你的 Controller 中需要覆蓋 handle(request,response,Object command,BindException) 方法,這個方法還需帶一個控制器命令參數,並且需要在構造函數中指定命令 類,如
public MyController(){
setCommandClass(MyCommand.class);
}
public MyController(){
setCommandClass(MyCommand.class);
}
在使用 command 對象與 Struts 中的 ActionForm是一樣的,也是通過處理方法來傳遞的,在 handle 方 法中用 MyCommand myCommand = (MyCommand)command。
命令對象只是一個 POJO,功能相當於 Struts 的 ActionForm,能匹配接受請求中的參數,它不需要 在 Spring 的配置文件中配置。留下一個疑問:要是 AbstractCommandController 能在 Spring 的配置 文件中注入可能要好些,相當於 Struts 的 Action 的 FormBean 也是在 struts-config.xml 配置給 Action 的
自己試了一下,可以通過配置給 commandClass 一個全限類名字符串注冊 class 屬性,Spring 提供 了相應的屬性編輯器(P258)
<property name="commandClass">
<value>com.unmi.MyCommand</value>
</property>
<property name="commandClass">
<value>com.unmi.MyCommand</value>
</property>
84. AbstractFormController(BaseCommandController的子類,所以也要設置 commandClass 屬性) 有一個子類 SimpleFormController,它聲明了兩個屬性 formView 和 successView,分別對應了在處理 請求出現異常和正常時對應的 View 的邏輯名,這兩個屬性需要在配置文件中給配上,在你的 SimpleFormController 類中覆蓋 void doSubmitAction(Object command) throws Exception 將會使用 到它們,注意這個方法沒有返回值的。你也可以覆蓋 ModelAndView onSubmit(Ojbect command),向 View 中傳遞數據,return new ModelAndView(getSuccessView(),"student",student); (P260)
85. AbstractFormController 可在接收到 HTTP GET 請求的時候顯示一個表單,轉向到 formView, 而在接收到一個 HTTP POST 請求是處理這個表單,轉向到 successView,處理時若驗證不通過返回到 formView。doSubmitAction(Object command) 只處理 HTTP POST 請求操作。(P259)
86. 驗證表單輸入, 你的驗證類必須實現 org.springframework.validation.Validator 接口, supports()方法幫助判斷驗證器是否適用於指定類,在 validate(Object command, Errors errors) 用 Errors 駁回任何非法數據。可使用 ValidationUtils.rejectIfXxx()、 ValidationUtils.invokeValidator() 方法或者是 Errors.reject()、Erros.rejectValue() 方法。如
ValidationUtils.rejectIfEmpty(errors, "login", "required.login" "Login is required");
if(!new Perl5util().match(PHONE_REGEXP,phone){
errors.reject ("invalide.phone","Phone number is invalid");
}
ValidationUtils.rejectIfEmpty (errors, "login", "required.login" "Login is required");
if(!new Perl5util().match (PHONE_REGEXP,phone){
errors.reject("invalide.phone","Phone number is invalid");
}
最後,你需要把驗證類注入給你的 CommandController 的 validator 屬性
<property name="validator">
<bean class="com.unmi.MyValidator"/>
</property>
<property name="validator">
<bean class="com.unmi.MyValidator"/>
</property>
validate 方法會在 AbstractCommandController.handleRequestInternal(request,response) 之前 調用,SimpleFormController.onSubmit() 會在調用 doSubmitAction() 之後,把 errors 傳遞給 View 。這裡的 Errors 就相當於 Struts 中的 ActionErros/ActionMessages。書中未提及如何在頁面顯示出 錯信息(P263)
87. P262 中寫的 StudentValidator 類有方法 validate()、validatePhone() 和 validateEmail() 方法,但是在 validate() 中卻沒有調用其他兩個 validateXxx() 方法。(P262)
88. 在討論下面的向導式表單之前,來閒話一下 Spring MVC。Spring MVC 相對它的 AOP 來控制事物 權限來說,名聲太小了些,多數人都會選擇用其他的 MVC 框架,如 Struts1/Strus2/WebWork/JSF 等, Spring MVC 只能說它與 IOC 結合緊密,實際的設計上似乎過於復雜,不易於使用。
89. 譬如 Controller 的類層次太多,繼承這個 Controller 類要實現這個方法,繼承那個 Controller 類要實現那個方法,有些麻煩。尤其是在維護代碼時,如果發現原有的 Controller 類不適 合現在場景需要切換到繼承另一個 Controller 時,要實現的方法名又得改改。對於容許多種 HandlerMapping (URL 映射到哪個 Controller) 的並存會讓開發者有時茫然不知所措,某個 URL 會導向 到哪裡不清淅。
90. Spring MVC 中把輸入驗證邏輯與數據對象分離,還是很值得肯定的。不過 Spring MVC 中用代碼 來校驗的做法這相比於 Struts 和 WebWork 中用配置方式來進行驗證要紙級一些。還不知道 Spring MVC 支不支持配置方式來驗證輸入數據的合法性。還有就是前面提過,ModelAndView 只適於傳遞一個屬性到 請求中,當有多個請求屬性仍需用 Servlet API 來塞值。