是什么
@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(); }