springboot的@RestControllerAdvice作用和捕获自定义异常返回自定义结果案例
创始人
2025-05-29 08:40:08

一、@RestControllerAdvice是什么?

@RestContrllerAdvice是一种组合注解,由@ControllerAdvice,@ResponseBody组成

@ControllerAdvice继承了@Component,反过来,可以理解为@RestContrllerAdvice本质上就是@Component

1.1 @Component是什么?

本质上是一个类,泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller,@Service等的时候),我们就可以使用@Component

作用就是实现bean注入,利用这个注解可以取代spring的xml配置文件

1.2 @Component案例

1.2.1 准备的jar

         com.alibabafastjson1.2.75

1.2.2 controller

@RestController
public class TestController {@Autowiredprivate TestService testService;@GetMapping("/test3")public String test3() {return testService.test();}
}

1.2.3 接口

public interface TestService {String test();
}

1.2.4组件

@Component
public class TestServiceImpl implements TestService {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic String test() {String b = null;try {b =  objectMapper.writeValueAsString("a");System.out.println(b);} catch (Exception e) {}return b;}
}

二、@RestControllerAdvice有什么作用?

  1. 自定义客户端返回格式

  1. 捕获客户端返回异常

三、@RestControllerAdvice案例和使用场景

捕获客户端返回异常案例(自定义返回异常)

3.1 未自定义捕获异常之前

3.2 自定义捕获异常以后

3.3代码实现自定义捕获异常

3.3.1 自定义异常枚举

public interface BaseCodeMsg {String getCode();String getMsg();
}
public enum PlatformExceptionMsgEnum implements BaseCodeMsg {/*** base平台返回的异常信息*/SELECT_NULL("000000001", "查询数据为空"),INVOKE_IS_REJECT("00000002", "请求被拒绝"),ILLEGAL_ARGUMENT_FORMAT("000000003", "非法参数格式"),ILLEGAL_ARGUMENT("000000004","数据非法"),SYSTEM_EXCEPTION("000000005", "系统异常");/*** 错误码*/private final String code;/*** 错误信息*/private final String msg;PlatformExceptionMsgEnum(String code, String msg) {this.code = code;this.msg = msg;}@Overridepublic String getCode() {return code;}@Overridepublic String getMsg() {return msg;}}

3.3.2 自定义平台异常

public abstract class AbstractApiException extends RuntimeException{public AbstractApiException() {}public abstract String getCode();public abstract String getMsg();
}
public class PlatformException extends AbstractApiException {private String code;private String msg;public PlatformException(BaseCodeMsg baseCodeMsg) {code = baseCodeMsg.getCode();msg = baseCodeMsg.getMsg();}public static void throwException(BaseCodeMsg baseCodeMsg) {throw new PlatformException(baseCodeMsg.getCode(), baseCodeMsg.getMsg());}public static void throwException(BaseCodeMsg baseCodeMsg, String msg) {throw new PlatformException(baseCodeMsg.getCode(), StringUtils.isEmpty(baseCodeMsg.getMsg()) ? msg : baseCodeMsg.getMsg());}public static void throwException(String code, String msg) {throw new PlatformException(code, msg);}public static void throwException(String msg) {throw new PlatformException(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION.getCode(), msg);}public PlatformException(String code, String msg) {this.code = code;this.msg = msg;}@Overridepublic String getCode() {return code;}@Overridepublic String getMsg() {return msg;}
}

3.3.3 自定义返回类

@Data
public class BaseResult implements Serializable {private static final long serialVersionUID = 1L;private String code;private String msg;private String traceId;private T data;public boolean isSuccess() {return PlatformExceptionMsgEnum.SUCCESS.getCode().equals(this.code);}public static BaseResult ok() {return restBaseResult((Object)null, PlatformExceptionMsgEnum.SUCCESS);}public static  BaseResult ok(T data) {return restBaseResult(data, PlatformExceptionMsgEnum.SUCCESS);}public static BaseResult fail() {return restBaseResult((Object)null, PlatformExceptionMsgEnum.SYSTEM_ERROR);}public static BaseResult fail(BaseCodeMsg baseCodeMsg) {return restBaseResult((Object)null, baseCodeMsg);}public static BaseResult fail(String code, String msg) {return restBaseResult((Object)null, code, msg);}private static  BaseResult restBaseResult(T data, BaseCodeMsg baseCodeMsg) {return restBaseResult(data, baseCodeMsg.getCode(), baseCodeMsg.getMsg());}private static  BaseResult restBaseResult(T data, String code, String msg) {BaseResult apiBaseResult = new BaseResult();apiBaseResult.setCode(code);apiBaseResult.setData(data);apiBaseResult.setMsg(msg);apiBaseResult.setTraceId(MDC.get("traceId"));return apiBaseResult;}public BaseResult() {}
}

3.3.4 controller层

@RestController
public class TestController {@GetMapping("/test")public void test() {PlatformException.throwException(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION);}}

3.3.5 @RestControllerAdvice

@RestControllerAdvice
@Configuration
public class GlobalExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);private MessageSource messageSource;/*** 捕获全局异常类** @param e* @return*/@ExceptionHandler({MethodArgumentNotValidException.class})public BaseResult handle(MethodArgumentNotValidException e) {if (e.getBindingResult().hasErrors()) {String msg = ((ObjectError) e.getBindingResult().getAllErrors().get(0)).getDefaultMessage();return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getCode(), this.getI18nMsg(msg));} else {log.info(e.getMessage(), e);return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getMsg()));}}/*** 捕获API调用接口的异常类** @param e* @return*/@ExceptionHandler(AbstractApiException.class)public BaseResult abstractApiException(AbstractApiException e) {return BaseResult.fail(e.getCode(), e.getMsg());}/*** 前端传入的参数和后端传入的参数接收不匹配** @param e* @return*/@ExceptionHandler({HttpMessageNotReadableException.class})public BaseResult handle(HttpMessageNotReadableException e) {log.warn(e.getMessage(), e);return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT_FORMAT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT_FORMAT.getMsg()));}/*** 子类异常(相当于子类不能抛出比父类更广泛异常)** @param e* @return*/@ExceptionHandler({UndeclaredThrowableException.class})public BaseResult handle(UndeclaredThrowableException e) {log.warn(e.getMessage(), e);return BaseResult.fail(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getMsg()));}/*** 异常捕获** @param e 捕获的异常,封装返回的对象* @return*/@ExceptionHandler(Exception.class)public BaseResult handleException(Exception e) {log.warn(e.getMessage(), e);StringJoiner joiner = new StringJoiner(":");joiner.add(this.getI18nMsg(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getMsg())).add(e.getMessage());return BaseResult.fail(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION.getCode(), joiner.toString());}private String getI18nMsg(String msg) {try {return this.messageSource.getMessage(msg, (Object[]) null, LocaleContextHolder.getLocale());} catch (NoSuchMessageException var3) {return msg;}}public GlobalExceptionHandler(MessageSource messageSource) {this.messageSource = messageSource;}
}

3.4 代码实现自定义返回结果

没有自定义返回结果之前

自定义返回结果以后

3.4.1 controller

@RestController
public class TestController {@GetMapping("/test2")public String test2() {return "test2";}}

3.4.2 返回结果来

BaseResult返回结果类在上面,对应需要导入json的jar也在上面

3.4.3 @RestControllerAdvice

@RestControllerAdvice(annotations = {RestController.class}
)
@Configuration
public class BaseResultResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;/*** @param methodParameter 利用这个参数判断注解信息* @param aClass* @return*/@Overridepublic boolean supports(MethodParameter methodParameter, Class> aClass) {return true;}/*** @param body               原controller需要返回的内容* @param methodParameter    利用这个参数判断注解信息* @param mediaType* @param aClass* @param serverHttpRequest* @param serverHttpResponse* @return*/@Overridepublic Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {try {if (methodParameter.getParameterType() == ResponseEntity.class) {return body;} else if (methodParameter.getParameterType() == BaseResult.class) {return body;} else if (methodParameter.getParameterType() == String.class) {serverHttpResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);return this.objectMapper.writeValueAsString(BaseResult.ok(body));} else {return BaseResult.ok(body);}} catch (Throwable t) {return BaseResult.fail();}}
}

四、拓展

@RestControllerAdvice的使用还可以指定对应的注解、包,类。比如你需要返回自定义结果格式,可以指定@RestController层使用,如果你要指定类和包也可以

4.1 指定注解

@RestControllerAdvice(annotations = {RestController.class}
)

4.2 指定类

@RestControllerAdvice(basePackageClasses = TestController.class
)

4.3 指定包

@RestControllerAdvice(basePackages = "com.common.base.controller"
)

相关内容

热门资讯

STM32F103指南者开发板... 1 前言 使用STM32F103指南者开发板,安装了Keil5,使用St...
二维数组的表现及应用 1 问题在Java数组中,数组是一种常遇见的表现形式。对于一维数组在最近的学习已经非常...
《程序员面试金典(第6版)》面... 题目描述 给定两个整型数字 N 与 M,以及表示比特位置的 i 与 j(...
什么叫丹霞地貌(中国七大丹霞景... 本篇文章极速百科给大家谈谈什么叫丹霞地貌,以及中国七大丹霞景区对应的知识点,希望对各位有所帮助,不要...
白色骐达mdashmdash好... 今天给各位分享白色骐达mdashmdash好看实用的两箱车的知识,其中也会对白色骐达改装图片进行解释...
裤子尺码28是多大(裤子尺码2... 本篇文章极速百科给大家谈谈裤子尺码28是多大,以及裤子尺码28是多大码对应的知识点,希望对各位有所帮...
进口奔驰s300价格多少(进口... 今天给各位分享进口奔驰s300价格多少的知识,其中也会对进口奔驰s300价格多少钱一辆进行解释,如果...
Keras 的模型(Model... 我们来做个 TensorFlow 的快速入门模型分享。 这次的学习目标就是模型构建的一些相关 API...
串行通信协议(I2C、SPI、... I2C(Inter-Integrated Circuit) 1.简单的双向两线制总线协议标准、半双...
石化团购:放价不打烊,14个汽... 今天给各位分享石化团购:放价不打烊,14个汽车品牌请您挑选!的知识,其中也会对石化团购的商品是真的吗...
tf金箔润唇膏是不是死亡芭比粉... 今天给各位分享tf金箔润唇膏是不是死亡芭比粉的知识,其中也会对tom ford金箔唇膏进行解释,如果...
日本也开始山寨了?造最强悍马,... 本篇文章极速百科给大家谈谈日本也开始山寨了?造最强悍马,比美国的还大一号!,以及日本山寨历史对应的知...
走应急车道一天内最多罚几次?应... 今天给各位分享走应急车道一天内最多罚几次?应急车道抓拍原理的知识,其中也会对应急车道行驶多久会被拍进...
代码分支管理:主干发布分支开发... 大家好,我是rainbowzhou。 上篇文章代码分支管理中,我介绍了3...
蓝桥杯C++组怒刷50道真题(... 🌼深夜伤感网抑云 - 南辰Music/御小兮 - 单曲 - 网易云音乐 ...
2015款林肯MKX空间怎么样... 本篇文章极速百科给大家谈谈2015款林肯MKX空间怎么样林肯MKX购车手册,以及2015款林肯mkx...
夏利n7怎么样能买么?的简单介... 今天给各位分享夏利n7怎么样能买么?的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘...
特斯拉宣布已在中国建立数据中心... 本篇文章极速百科给大家谈谈特斯拉宣布已在中国建立数据中心,以实现数据存储本地...,以及特斯拉中国数...
算法--最长回文子串--jav... 这个算法题里面总是有 暴力解法 把所有字串都拿出来判断一下 这里有小小的优化: 就是当...
雷凌豪华版混动:外观空间出色,... 本篇文章极速百科给大家谈谈雷凌豪华版混动:外观空间出色,动力油耗佳,操控稳定...,以及雷凌豪华版混...
时序预测 | MATLAB实现... 时序预测 | MATLAB实现NARX非线性自回归外生模型和MLP多层感知器预测比较 目录 时序...
字符串函数的模拟实现 文章目录前言函数介绍strlen 函数strcpy 函数strcat 函数strcmp函数strnc...
3月13~19日学习总结 关于Jenetics库的学习 这是一个开源的遗传算法库,可以使用maven直接引入的项...
锅盖发型(锅盖发型图片男) 锅... 今天给各位分享锅盖发型的知识,其中也会对锅盖发型图片男进行解释,如果能碰巧解决你现在面临的问题,别忘...
干式双离合变速箱寿命是多久(干... 本篇文章极速百科给大家谈谈干式双离合变速箱寿命是多久,以及干式双离合变速箱寿命技术过关了吗对应的知识...
飞碟Q2V飞碟Q2V最新报价-... 今天给各位分享飞碟Q2V飞碟Q2V最新报价-图片-参数的知识,其中也会对飞碟20进行解释,如果能碰巧...
车辆识别代码是车架号吗(车辆识... 今天给各位分享车辆识别代码是车架号吗的知识,其中也会对车辆识别代码是车架号吗怎么看进行解释,如果能碰...
【洛谷刷题】蓝桥杯专题突破-深... 目录 写在前面: 题目:P1149 [NOIP2008 提高组] 火柴棒...
Gocator 3D线扫相机专... 文章目录3D相机标定用物品规范GOCATOR 2880Gocator 电源/LAN连接器Gocato...
Activity工作流(三):... 3. Service服务 所有的Service都通过流程引擎获得。 3.1 Repositor...