Spring注解之@RestControllerAdvice
前言
前段时间部门搭建新系统,需要出异常后统一接口的返回格式,于是用到了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的合并。此注解通过对异常的拦截实现的统一异常返回处理,如果大家在项目中有类似的需求,不妨试一下,好用又方便。