是什麼
@RestControllerAdvice 統一異常處理
@RestControllerAdvice是一個組合注解,由@ControllerAdvice、@ResponseBody組成
ControllerAdvice和RestControllerAdvice的差別
兩者都是全局捕獲異常,但是RestControllerAdvice更加強大,其作用相當于ControllerAdvice+ResponseBody
basePackages: 指定一個或多個包,這些包及其子包下的所有 Controller 都被該 @ControllerAdvice 管理
@ExceptionHandler(value = Exception.class) ExceptionHandler的作用是用來捕獲指定的異常。
為什麼要有這個注解
對于異常處理情況,我們也需要統一成上面的格式。如果我們在controller中通過try catch來處理異常的話,會出現一個問題就是每個函數裡都加一個Try catch,代碼會變的很亂。下面我們就通過spring boot的注解來省略掉controller中的try-catch 幫助我們來封裝異常資訊并傳回給前端,這樣使用者也不會得到一些奇奇怪怪的錯誤提示。
怎麼用
假設有枚舉
public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000,"系統未知異常"),
VAILD_EXCEPTION(10001,"參數格式校驗失敗");
private int code;
private String msg;
BizCodeEnume(int code,String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
控制層
/**
* 儲存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
if(result.hasErrors()){
//1.擷取校驗錯誤的結果
Map<String, String> map = new HashMap<>();
result.getFieldErrors().forEach((item)->{
//FieldError擷取到錯誤的提示
String message = item.getDefaultMessage();
//擷取錯誤的屬性的名字
String field = item.getField();
map.put(field,message);
System.out.println("******");
});
return R.error(400,"送出的資料不合法").put("data",map);
}
brandService.save(brand);
return R.ok();
}
這個控制層主要是接受請求對象儲存到資料庫中,為防止老6跳過前端的頁面,用postman發送請求。需要對請求對象進行判斷 ,這裡直接在BrandEntity 這個類上用
/**
* jsr303
* 1)給bean添加校驗注解,并定義自己的message提示
* 2)開啟校驗功能@valid
* 效果:校驗錯誤以後會有預設的響應
* 3)給校驗的bean後緊跟一個bindingResult ,就可以擷取到校驗結果
*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必須送出")
private String name;
/**
* 品牌logo位址
*/
@NotEmpty
@URL(message = "logo必須是一個url位址")
private String logo;
/**
* 介紹
*/
private String descript;
/**
* 顯示狀态[0-不顯示;1-顯示]
*/
@NotNull
private Integer showStatus;
/**
* 檢索首字母
*/
@NotEmpty
@Pattern(regexp = "/^[a-zA-Z]$/",message = "檢索首字母必須是首字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0,message = "排序必須大于等于0")
private Integer sort;
}
大家可以看到在控制層的判斷還是十分繁瑣 ,這個時候使用@RestControllerAdvice 解決
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e){
Map<String, String> map = new HashMap<>();
log.error("資料校驗出現問題{},異常類型:{}",e.getMessage(),e.getClass());
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach((item)->{
map.put(item.getField(),item.getDefaultMessage());
});
return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",map);
}
@ExceptionHandler(value = Throwable.class)
public R all(Exception e){
log.error("出現問題{},異常類型:{}",e.getMessage(),e.getClass());
return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
}
}
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand/*, BindingResult result*/){
// if(result.hasErrors()){
// //1.擷取校驗錯誤的結果
// Map<String, String> map = new HashMap<>();
// result.getFieldErrors().forEach((item)->{
// //FieldError擷取到錯誤的提示
// String message = item.getDefaultMessage();
// //擷取錯誤的屬性的名字
// String field = item.getField();
// map.put(field,message);
// System.out.println("******");
// });
// return R.error(400,"送出的資料不合法").put("data",map);
// }
brandService.save(brand);
return R.ok();
}