在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 注解的全局数据预处理来解决这个问题.