SpringMVC 中 @ControllerAdvice 注解

在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping、@PostMapping, @GetMapping注解中。
@ControllerAdvice 注解有以下3种功能:

  • 全局异常处理
  • 全局数据绑定
  • 全局数据预处理

全局异常处理

编写自定义异常类

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类的异常才会进行事务回滚,所以我们一般自定义异常都继承该异常类。

编写全局异常处理类

@ControllerAdvice
public class MyExceptionHandler {
    @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;
    }
}

使用@ExceptionHandler注解传入的参数可以一个数组,且使用该注解时,传入的参数不能相同,也就是不能使用两个@ExceptionHandler去处理同一个异常。如果传入参数相同,则初始化ExceptionHandler时会失败。

在微服务中,全局异常处理通常放在一个公共服务中,其他微服务使用,只需要引入依赖即可.需要注意的一点是所在包名需要和微服务启动类平级或者是子级, 否则扫描不到注解,就不会生效.

测试

@Controller
public class DemoController {
  
    @GetMapping("/test")
    public String testTwo() {
        throw new CustomException(500L, "系统发生500异常!");
    }
}

启动应用,访问localhost:8080/test.返回报文为:

{“msg”:“系统发生500异常!”,“code”:500}

全局数据预处理

场景一:

假设有两个实体类, Book 和 Author,分别定义如下:

public class Book {
    private String name;
    private Long price;
    //getter/setter
}
public class Author {
    private String name;
    private Integer age;
    //getter/setter
}

注意两个实体类中有同名的属性, 当我们第一如下的Controller层接口时:

@PostMapping("/book")
public void addBook(Book book, Author author) {
    System.out.println(book);
    System.out.println(author);
}

前端请求发送的数据,无法区分name属性. 我们就可以通过 @ControllerAdvice 注解的全局数据预处理来解决这个问题.

场景一的解决方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值