springboot 詳解RestControllerAdvice(ControllerAdvice)攔截異常並統一處理
簡介
@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 {}; }
作為特化@Component,允許通過類路徑掃描自動檢測實現類。
它通常用於定義@ExceptionHandler, @InitBinder 和 @ModelAttribute 適用於所有@RequestMapping方法的方法。
annotations(),basePackageClasses(), basePackages()或它的別名value() 可以被指定,以限定控制器,以協助的特定子集。當應用多個選擇器時,應用OR邏輯 - 意味着所選的控制器應匹配至少一個選擇器。
默認行為(即,如果沒有任何選擇器使用),帶@ControllerAdvice注釋的類將協助所有已知的控制器。
背景
當我們定義了一個自定義返回參數格式時,希望得到統一的返回,如果在運行時發現了異常,也希望將異常統一返回。如
期望返回格式:
{ "msg": "success", "code": 500, "success": false, "message": "id不能為空!" }
拋出異常格式:
{ "timestamp": "2019-04-01T07:17:38.619+0000", "status": 500, "error": "Internal Server Error", "message": "id不能為空!", "path": "/api/myInfo" }
如何讓我們的異常得到期望的返回格式,這里就需要用到了@ControllerAdvice或者RestControllerAdvice(如果全部異常處理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,這樣在方法上就可以不需要添加 @ResponseBody。)。下面看一個demo。
准備工作
1.創建一個UnionExceptionHandler類,定義全局異常捕捉處理。
package com.honghh.bootfirst.exception; import com.honghh.bootfirst.utils.R; import lombok.extern.slf4j.Slf4j; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * ClassName: UnionExceptionHandler * Description: * * @author honghh * @date 2019/04/01 10:03 */ @Slf4j @RestControllerAdvice public class UnionExceptionHandler { /** * 應用到所有@RequestMapping注解方法,在其執行之前初始化數據綁定器 * * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) { log.info("binder.getFieldDefaultPrefix {}",binder.getFieldDefaultPrefix()); log.info("binder.getFieldMarkerPrefix {}",binder.getFieldMarkerPrefix()); } /** * 把值綁定到Model中,使全局@RequestMapping可以獲取到該值 * @param model */ @ModelAttribute public void addAttributes(Model model) { model.addAttribute("author", "harry"); } /** * Description : 全局異常捕捉處理 * Group : * * @author honghh * @date 2019/4/1 0001 10:34 * @param ex * @return */ @ExceptionHandler(RRException.class) public R apiExceptionHandler(RRException ex) { log.error("ApiException 異常拋出:{}", ex); return R.fail(ex); }
/**
* Description : 針對某個異常捕捉處理
* Group :
*
* @author honghh
* @date 2019/4/1 0001 10:34
* @param ex
* @return
*/
@ExceptionHandler(SSException.class) public R apiExceptionHandler(SSException ex) { log.error("ApiException 異常拋出:{}", ex); return R.fail(ex); }
}
啟動應用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都會作用在 @RequestMapping 注解的方法上。
@ModelAttribute:在Model上設置的值,對於所有被 @RequestMapping 注解的方法中,都可以通過 ModelMap 獲取
2.創建一個RRException 自定義異常。
package com.honghh.bootfirst.exception;
/** * 自定義異常 * * @author harry * @date 2018-07-20 16:30 */ public class RRException extends RuntimeException { private static final long serialVersionUID = 1L; private String msg; private int code = 500; public RRException(String msg) { super(msg); this.msg = msg; } public RRException(String msg, Throwable e) { super(msg, e); this.msg = msg; } public RRException(String msg, int code) { super(msg); this.msg = msg; this.code = code; } public RRException(String msg, int code, Throwable e) { super(msg, e); this.msg = msg; this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
3.寫一個RequestMapping方法,拋出異常進行測試。[spring boot 默認情況下會映射到 /error 進行異常處理,但是提示並不十分友好,下面自定義異常處理,提供友好展示。
@GetMapping("myInfo")
public R myInfo(@RequestParam Integer id) {
if (id == null) {
throw new RRException("id不能為空!");
}
MyInfo myInfo = myInfoService.getById(id);
return R.ok().put("myInfo", myInfo);
}
//啟動應用,訪問:http://127.0.0.1:8080/api/myInfo?id= ,正常顯示以下json內容,證明自定義異常已經成功被攔截。
{
"msg": "success",
"code": 500,
"success": false,
"message": "id不能為空!"
}
代碼獲取
https://gitee.com/honghh/boot-demo.git
參考文獻
https://docs.spring.io/spring-framework/docs/5.0.0.M1/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
————————————————
版權聲明:本文為CSDN博主「AH_HH」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_35098526/article/details/88949425
