springboot 詳解RestControllerAdvice(ControllerAdvice)(轉)


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM