精通Spring Boot —— 第十五篇:自定義異常處理

在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 註解,能夠用於定義@ExceptionHandler、@InitBinder、@ModelAttribute,並應用到全部@RequestMapping、@PostMapping, @GetMapping註解中。 接下來我將經過代碼展現如何使用這些註解,以及處理異常。html

1.註解的介紹

先定義一個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

2.異常的處理

###編寫自定義異常類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的瀟灑人生。 關注了也不必定更新,更新就不得了了。 qrcode_for_gh_2bd3f44efa21_258瀏覽器

相關文章
相關標籤/搜索