Spring3.2開始提供的新註解,控制器加強(AOP),最主要的應用是作統一的異常處理。@ControllerAdvice
(當作spring mvc提供的一個特殊的攔截器)。
@ControllerAdvice
是一個@Component
,用於定義@ExceptionHandler
(最主要用途),@InitBinder
和@ModelAttribute
方法,適用於全部使用@RequestMapping
方法(攔截)。
引伸:@interface
元註解@Target(ElementType.TYPE)
:該註解應用到什麼地方。@Retention(RetentionPolicy.RUNTIME)
:何時應用。html
@ExceptionHandler
:爲全部controller封裝統一異常處理代碼。@ModelAttribute
:爲全部controller設置全局變量。@InitBinder
:用於爲全部controller設置某個類型的數據轉換器。java
準備:搭建好Spring Boot,頁面使用thymeleafspring
ControllerAdviceTest.java瀏覽器
/** * 啓動應用後,被 @ExceptionHandler、@InitBinder、@ModelAttribute 註解的方法, * 都會做用在 被 @RequestMapping 註解的方法上 */ @ControllerAdvice public class ControllerAdviceTest { /** * 全局異常捕捉處理 * @ExceptionHandler 用來定義函數針對的異常類型 * @param ex * @return */ @ResponseBody @ExceptionHandler(value = Exception.class) public Map errorHandler(Exception ex){ Map map = new HashMap(); map.put("code","0000"); map.put("msg",ex.getMessage()); return map; } }
ExceptionController.java服務器
@RestController public class ExceptionController { @RequestMapping("exception1") public String exception1() throws IOException { return "攔截器測試"; } }
瀏覽器訪問:localhost:8080/exception1mvc
瀏覽器顯示:攔截器測試app
@RestController public class ExceptionController { @RequestMapping("exception2") public String exception2() throws IOException { int i = 1/0; return "攔截器測試"; } }
瀏覽器訪問:localhost:8080/exception2編輯器
瀏覽器顯示:{"msg":"/ by zero","code":"0000"}函數
@RestController public class ExceptionController { @RequestMapping("exception3") public String exception3() throws IOException { throw new NullPointerException("服務器到非洲去了"); } }
瀏覽器訪問:localhost:8080/exception3測試
瀏覽器顯示:{"msg":"服務器到非洲去了","code":"0000"}
MyException.java
public class MyException extends RuntimeException { private String code; private String msg; //Get、Set方法略…… public MyException(String code,String msg) { this.code = code; this.msg = msg; } }
ControllerAdviceTest.java
@ControllerAdvice public class ControllerAdviceTest { /** * 攔截捕捉自定義異常 MyException.class * @param ex * @return */ @ResponseBody @ExceptionHandler(value = MyException.class) public Map myErrorHandler(MyException ex) { Map map = new HashMap(); map.put("code", ex.getCode()); map.put("msg", ex.getMsg()); return map; } }
ExceptionController.java
@RestController public class ExceptionController { @RequestMapping("myException") public String myException(){ throw new MyException("1111","This is my Exception!"); } }
瀏覽器訪問:localhost:8080/myException
瀏覽器顯示:{"msg":"This is my Exception!","code":"1111"}
跳轉到一個單獨的異常顯示頁面
ControllerAdviceTest.java
@ControllerAdvice public class ControllerAdviceTest { /** * 跳轉視圖顯示異常 * @param ex * @return */ @ExceptionHandler(value = MyException.class) public ModelAndView myErrorHandlerToView(MyException ex) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("myGlobalExceptionPage"); modelAndView.addObject("code", ex.getCode()); modelAndView.addObject("msg", ex.getMsg()); return modelAndView; } }
myGlobalExceptionPage.html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>myGlobalExceptionPage</title> </head> <body> <p th:text="${code}"></p> <p th:text="${msg}"></p> </body> </html>
瀏覽器訪問:localhost:8080/myException
瀏覽器顯示:1111 This is my Exception!
ControllerAdviceTest.java
@ControllerAdvice public class ControllerAdviceTest { /** * 把值綁定到Model中,使全局@RequestMapping能夠獲取到該值 * @param model */ @ModelAttribute public void addAttributes(Model model) { System.out.println("添加全局變量"); model.addAttribute("userName", "Jack"); } }
ExceptionController.java
@RestController public class ExceptionController { /** * 使用注入的ModelMap來取變量 * @param modelMap * @return */ @RequestMapping("modelMapTest1") public Object modelMapTest1(ModelMap modelMap){ Object globalVal = modelMap.get("userName"); System.out.println("全局變量爲:"+globalVal); return globalVal; } }
瀏覽器訪問:localhost:8080/modelMapTest1
控制檯輸出:添加全局變量 全局變量爲:Jack
瀏覽器顯示:Jack
ExceptionController.java
@RestController public class ExceptionController { /** * 也能夠使用@ModelAttribute註解來取變量 * @param globalVal * @return */ @RequestMapping("/modelMapTest2") public Object modelMapTest2(@ModelAttribute("userName") String globalVal) { System.out.println("全局變量爲:"+globalVal); return globalVal; } }
瀏覽器訪問:localhost:8080/modelMapTest2
控制檯輸出:添加全局變量 全局變量爲:Jack
瀏覽器顯示:Jack
ControllerAdviceTest.java
@ControllerAdvice public class ControllerAdviceTest { /** * 應用到全部@RequestMapping註解方法,在其執行以前初始化數據綁定器 * WebDataBinder是用來綁定請求參數到指定的屬性編輯器 * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) { System.out.println("initBinder執行"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); //日期格式是否寬容(只能判斷是否須要跳到下個月去) /* * spring mvc在綁定表單以前,都會先註冊這些編輯器, * Spring本身提供了大量的實現類,諸如CustomDateEditor,CustomBooleanEditor,CustomNumberEditor等 * 使用時候調用WebDataBinder的registerCustomEditor方法註冊 */ binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false)); } }
ExceptionController.java
@RestController public class ExceptionController { @RequestMapping("/date") public Date index(Date date){ System.out.println("date="+date); return date; } }
瀏覽器訪問:localhost:8080/date?date=2019-3-20
控制檯輸出:initBinder執行 date=2019-3-20
瀏覽器顯示:"2019-3-20"