與Spring AOP同樣,Spring MVC也可以給控制器加入通知,它主要涉及4個註解:
•@ControllerAdvice,主要做用於類,用以標識全局性的控制器的攔截器,它將應用於對應的控制器。
•@InitBinder,是一個容許構建POJO參數的方法,容許在構造控制器參數的時候,加入必定的自定義控制。
•@ExceptionHandler,經過它能夠註冊一個控制器異常,使用當控制器發生註冊異常時,就會跳轉到該方法上。
•@ModelAttribute,是一種針對於數據模型的註解,它先於控制器方法運行,當標註方法返回對象時,它會保存到數據模型中。java
代碼清單16-19:控制器通知web
package com.ssm.chapter15.controller.advice; //標識控制器通知,而且指定對應的包 import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import java.text.SimpleDateFormat; import java.util.Date; @ControllerAdvice(basePackages = {"com.ssm.chapter15.controller.advice"}) public class CommonControllerAdvice { //定義HTTP對應參數處理規則 @InitBinder public void initBinder(WebDataBinder binder) { //針對日期類型的格式化,其中CustomDateEditor是客戶自定義編輯器 // 它的boolean參數表示是否容許爲空 binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), false)); } //處理數據模型,若是返回對象,則該對象會保存在 @ModelAttribute public void populateModel(Model model) { model.addAttribute("projectName", "chapter15"); } //異常處理,使得被攔截的控制器方法發生異常時,都能用相同的視圖響應 @ExceptionHandler(Exception.class) public String exception() { return "exception"; } }
代碼清單16-20:測試控制器通知spring
package com.ssm.chapter15.controller.advice; import org.apache.http.client.utils.DateUtils; import org.springframework.format.annotation.NumberFormat; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("/advice") public class MyAdviceController { /** * http://localhost:8081/advice/test.do?date=2017-06-23%2018:12:00&amount=123,456.78 * @param date 日期,在@initBinder 綁定的方法有註冊格式 * @param model 數據模型,@ModelAttribute方法會先於請求方法運行 * @return map */ @RequestMapping("/test") @ResponseBody public Map<String, Object> testAdvice(Date date, @NumberFormat(pattern = "##,###.00") BigDecimal amount, Model model) { Map<String, Object> map = new HashMap<String, Object>(); //因爲@ModelAttribute註解的通知會在控制器方法前運行,因此這樣也會取到數據 map.put("project_name", model.asMap().get("projectName")); // map.put("date", DateUtils.format(date, "yyyy-MM-dd")); map.put("date", DateUtils.formatDate(date, "yyyy-MM-dd")); map.put("amount", amount); return map; } /** * 測試異常. */ @RequestMapping("/exception") public void exception() { throw new RuntimeException("測試異常跳轉"); } }
控制器(註解@Controller)也可使用@Init-Binder、@ExceptionHandler、@ModelAttribute。注意,它只對於當前控制器有效數據庫
代碼清單16-21:測試@ModelAttributeapache
package com.ssm.chapter15.controller; import com.ssm.chapter15.pojo.Role; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "/role2") public class Role2Controller { // @Autowired // private RoleService roleService = null; /** * 在進入控制器方法前運行,先從數據庫中查詢角色,而後以鍵role保存角色對象到數據模型 * * @param id 角色編號 * @return 角色 */ @ModelAttribute("role") public Role initRole(@RequestParam(value = "id", required = false) Long id) { //判斷id是否爲空 if (id == null || id < 1) { return null; } // Role role = roleService.getRole(id); Role role = new Role(id, "射手", "遠程物理輸出"); return role; } /** * http://localhost:8081/role2/getRoleFromModelAttribute.do?id=1 * * @param role 從數據模型中取出的角色對象 * @return 角色對象 * @ModelAttribute 註解從數據模型中取出數據 */ @RequestMapping(value = "getRoleFromModelAttribute") @ResponseBody public Role getRoleFromModelAttribute(@ModelAttribute("role") Role role) { return role; } }
package com.ssm.chapter15.exception; //新增Spring MVC的異常映射,code表明異常映射碼,而reason則表明異常緣由 import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "找不到角色信息異常!!") public class RoleException extends RuntimeException { private static final long serialVersionUID = 5040949196309781680L; }
package com.ssm.chapter15.controller; import com.ssm.chapter15.exception.RoleException; import com.ssm.chapter15.pojo.Role; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller @RequestMapping(value = "/roleE") public class RoleExceptionController { /** * http://localhost:8081/roleE/notFound.do?id=1 * * @param id * @return */ @RequestMapping("notFound") @ResponseBody public Role notFound(Long id) { // Role role = roleService.getRole(id); Role role = new Role(id, "射手", "遠程物理輸出"); role = null; //找不到角色信息拋出RoleException if (role == null) { throw new RoleException(); } return role; } //當前控制器發生RoleException異常時,進入該方法 @ExceptionHandler(RoleException.class) public String HandleRoleException(RoleException e) { //返回指定的頁面,避免不友好 return "exception"; } }