在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 註解,能夠用於定義@ExceptionHandler、@InitBinder、@ModelAttribute,並應用到全部@RequestMapping、@PostMapping, @GetMapping註解中。 接下來我將經過代碼展現如何使用這些註解,以及處理異常。html
先定義一個ControllerAdvice。代碼以下java
/** * @author Lensen * @desc * @since 2018/10/5 11:01 */ @ControllerAdvice public class MyExceptionHandler { /** * 應用到全部@RequestMapping註解方法,在其執行以前初始化數據綁定器 * @param binder */ @InitBinder public void initWebBinder(WebDataBinder binder){ //對日期的統一處理 binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); //添加對數據的校驗 //binder.setValidator(); } /** * 把值綁定到Model中,使全局@RequestMapping能夠獲取到該值 * @param model */ @ModelAttribute public void addAttribute(Model model) { model.addAttribute("attribute", "The Attribute"); } /** * 捕獲CustomException * @param e * @return json格式類型 */ @ResponseBody @ExceptionHandler({CustomException.class}) //指定攔截異常的類型 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定義瀏覽器返回狀態碼 public Map<String, Object> customExceptionHandler(CustomException e) { Map<String, Object> map = new HashMap<>(); map.put("code", e.getCode()); map.put("msg", e.getMsg()); return map; } /** * 捕獲CustomException * @param e * @return 視圖 */ // @ExceptionHandler({CustomException.class}) // public ModelAndView customModelAndViewExceptionHandler(CustomException e) { // Map<String, Object> map = new HashMap<>(); // map.put("code", e.getCode()); // map.put("msg", e.getMsg()); // ModelAndView modelAndView = new ModelAndView(); // modelAndView.setViewName("error"); // modelAndView.addObject(map); // return modelAndView; // } }
須要注意的是使用@ExceptionHandler註解傳入的參數能夠一個數組,且使用該註解時,傳入的參數不能相同,也就是不能使用兩個@ExceptionHandler去處理同一個異常。若是傳入參數相同,則初始化ExceptionHandler時會失敗。 對於@ControllerAdvice註解,咱們來看看源碼的定義:git
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] assignableTypes() default {}; Class<? extends Annotation>[] annotations() default {}; }
咱們能夠傳遞basePackage,聲明的類(是一個數組)指定的Annotation參數,具體參考:spring framework docgithub
###編寫自定義異常類web
package com.developlee.errorhandle.exception; /** * @author Lensen * @desc 自定義異常類 * @since 2018/10/5 11:04 */ public class CustomException extends RuntimeException { private long code; private String msg; public CustomException(Long code, String msg){ this.code = code; this.msg = msg; } public long getCode() { return code; } public void setCode(long code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
Spring 對於 RuntimeException類的異常纔會進行事務回滾,因此咱們通常自定義異常都繼承該異常類。spring
/** * @author Lensen * @desc * @since 2018/10/5 11:01 */ @ControllerAdvice("com.developlee.errorhandle") public class MyExceptionHandler { /** * 應用到全部@RequestMapping註解方法,在其執行以前初始化數據綁定器 * @param binder */ @InitBinder public void initWebBinder(WebDataBinder binder){ } /** * 把值綁定到Model中,使全局@RequestMapping能夠獲取到該值 * @param model */ @ModelAttribute public void addAttribute(Model model) { model.addAttribute("attribute", "The Attribute"); } /** * 捕獲CustomException * @param e * @return json格式類型 */ @ResponseBody @ExceptionHandler({CustomException.class}) //指定攔截異常的類型 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定義瀏覽器返回狀態碼 public Map<String, Object> customExceptionHandler(CustomException e) { Map<String, Object> map = new HashMap<>(); map.put("code", e.getCode()); map.put("msg", e.getMsg()); return map; } /** * 捕獲CustomException * @param e * @return 視圖 */ // @ExceptionHandler({CustomException.class}) // public ModelAndView customModelAndViewExceptionHandler(CustomException e) { // Map<String, Object> map = new HashMap<>(); // map.put("code", e.getCode()); // map.put("msg", e.getMsg()); // ModelAndView modelAndView = new ModelAndView(); // modelAndView.setViewName("error"); // modelAndView.addObject(map); // return modelAndView; // } }
在controller中拋出自定義異常json
/** * @author Lensen * @desc * @since 2018/10/5 11:00 */ @Controller public class DemoController { /** * 關於@ModelAttribute, * 能夠使用ModelMap以及@ModelAttribute()來獲取參數值。 */ @GetMapping("/one") public String testError(ModelMap modelMap ) { throw new CustomException(500L, "系統發生500異常!" + modelMap.get("attribute")); } @GetMapping("/two") public String testTwo(@ModelAttribute("attribute") String attribute) { throw new CustomException(500L, "系統發生500異常!" + attribute); } }
啓動應用,範圍localhost:8080/one.返回報文爲:api
{"msg":"系統發生500異常!The Attribute","code":500}
可見咱們的@InitBinder和@ModelAttribute註解生效。且自定義異常被成功攔截。若是所有異常處理都返回json,那麼能夠使用 @RestControllerAdvice 代替 @ControllerAdvice ,這樣在方法上就能夠不須要添加 @ResponseBody。@RestControllerAdvice在註解上已經添加了@ResponseBody。數組
最後,以上示例代碼可在個人github.com中找到。 個人我的公衆號:developlee的瀟灑人生。 關注了也不必定更新,更新就不得了了。 瀏覽器