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的合并。此注解通过对异常的拦截实现的统一异常返回处理,如果大家在项目中有类似的需求,不妨试一下,好用又方便。

posted on 2019-11-16 22:56  淡墨痕  阅读(2149)  评论(0编辑  收藏  举报