前言
前段时间部门搭建新系统,需要出异常后统一接口的返回格式,于是用到了Spring的注解@RestControllerAdvice。现在把此注解的用法总结一下。
用法
首先定义返回对象ResponseDto
1 package com.staff.points.common;
2
3 import lombok.Data;
4
5 import java.io.Serializable;
6
7 @Data
8 public class ResponseDto<T> implements Serializable {
9 private static final long serialVersionUID = -284719732991678911L;
10
11 private String code;
12
13 private String message;
14
15 private T data;
16
17 public static <T> ResponseDto<T> assemblingSuccessResponse(T data) {
18 ResponseDto<T> responseDto = new ResponseDto<>();
19 responseDto.setCode(ResponseCodeEnum.SUCCESS.getCode());
20 responseDto.setMessage(ResponseCodeEnum.SUCCESS.getMessage());
21 responseDto.setData(data);
22 return responseDto;
23 }
24
25 public static <T> ResponseDto<T> assemblingSuccessResponse() {
26 ResponseDto<T> responseDto = new ResponseDto<>();
27 responseDto.setCode(ResponseCodeEnum.SUCCESS.getCode());
28 responseDto.setMessage(ResponseCodeEnum.SUCCESS.getMessage());
29 responseDto.setData(null);
30 return responseDto;
31 }
32
33 public static <T> ResponseDto<T> assemblingFailureResponse(ResponseCodeEnum data) {
34 ResponseDto<T> responseDto = new ResponseDto<>();
35 responseDto.setCode(data.FAILURE.getCode());
36 responseDto.setMessage(data.FAILURE.getMessage());
37 return responseDto;
38 }
39
40 public static <T> ResponseDto<T> assemblingFailureResponse() {
41 ResponseDto<T> responseDto = new ResponseDto<>();
42 responseDto.setCode(ResponseCodeEnum.FAILURE.getCode());
43 responseDto.setMessage(ResponseCodeEnum.FAILURE.getMessage());
44 return responseDto;
45 }
46 }
然后定义返回码的枚举类,此处只定义了两种,有需要可以往下添加很多。
1 package com.staff.points.common;
2
3 import lombok.AllArgsConstructor;
4 import lombok.Getter;
5
6 @AllArgsConstructor
7 @Getter
8 public enum ResponseCodeEnum {
9 SUCCESS("00", "成功"),
10 FAILURE("01", "系统异常");
11
12
13 private String code;
14 private String message;
15 }
下面是自定义的异常类
1 package com.staff.points.common;
2
3 import lombok.Data;
4
5 @Data
6 public class StaffPointsException extends RuntimeException{
7 private String code;
8 private String message;
9 public StaffPointsException () {}
10
11 public StaffPointsException (Exception e) {
12 super(e);
13 }
14
15 public StaffPointsException (String code, String message) {
16 super(message);
17 this.code = code;
18 this.message = message;
19 }
20
21 public StaffPointsException (ResponseCodeEnum codeEnum) {
22 super(codeEnum.getMessage());
23 this.code = codeEnum.getCode();
24 this.message = codeEnum.getMessage();
25 }
26 }
然后是关键的@RestControllerAdvice修饰的类
1 package com.staff.points.exception;
2
3 import com.staff.points.common.ResponseCodeEnum;
4 import com.staff.points.common.ResponseDto;
5 import com.staff.points.common.StaffPointsException;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8 import org.springframework.stereotype.Component;
9 import org.springframework.web.bind.annotation.ExceptionHandler;
10 import org.springframework.web.bind.annotation.RestControllerAdvice;
11
12 @RestControllerAdvice
13 @Component
14 public class UnifyExceptionHandler {
15 private Logger logger = LoggerFactory.getLogger(UnifyExceptionHandler.class);
16
17 @ExceptionHandler(Exception.class)
18 public ResponseDto handlerCommonException (Exception e) {
19 ResponseDto responseDto = new ResponseDto<>();
20 responseDto.setCode(ResponseCodeEnum.FAILURE.getCode());
21 responseDto.setMessage(ResponseCodeEnum.FAILURE.getMessage());
22 logger.info("UnifyExceptionHandler.handlerCommonException exception:" + e);
23 return responseDto;
24 }
25 // 报StaffPointException时,对其进行拦截并处理的方法
26 @ExceptionHandler(StaffPointsException.class)
27 public ResponseDto handlerCustomizeException (StaffPointsException e) {
28 ResponseDto responseDto = new ResponseDto<>();
29 responseDto.setCode(e.getCode());
30 responseDto.setMessage(e.getMessage());
31 logger.info("UnifyExceptionHandler.handlerCustomizeException StaffPointsException:" + e);
32 return responseDto;
33 }
34 }
运行代码时,如果出现了StaffPointException,那么就会被拦截进入第27行的方法(就是说可以自由的在业务代码里往外throw自定义异常了);如果出现了其他的异常,则进入18行的方法,统一返回。
验证一下,在代码里造一个NPE异常时,返回结果:
1 {
2 "code": "01",
3 "message": "系统异常",
4 "data": null
5 }
造一个StaffPointsException异常时,返回结果:
1 {
2 "code": "99",
3 "message": "自定义业务异常",
4 "data": null
5 }
它的作用原理,大体是先在spring初始化时将类扫描进容器,出异常后,在DispatcherServlet类的doDispatch方法中调用了对异常的拦截处理。
小结
看@RestControllerAdvice源码可以知道,它就是@ControllerAdvice和@ResponseBody的合并。此注解通过对异常的拦截实现的统一异常返回处理,如果大家在项目中有类似的需求,不妨试一下,好用又方便。