SpringBoot异样对立解决
本文基于SpringBoot返回对立后果包装 有一些类在上文中曾经创立,这里不再赘述。(这是一篇长篇连载文)
下面咱们咱们介绍了对立返回格局,如果程序抛异样了,咱们是否也能够返回对立的格局呢?
答案是,当然能够的,不光能够抛出咱们想要的格局,还能够对指定的异样类型进行非凡解决
例如应用@Validated对入参校验的异样,咱们自定义的异样等等
未解决的返回状况
首先咱们模仿一个异样的场景,代码如下
package com.maple.demo.controller;import lombok.Data;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @author 笑小枫 * @date 2022/07/15 */@RestController@RequiredArgsConstructor@RequestMapping("/example")public class TestErrorResultController { /** * 模拟系统空指针异样 */ @GetMapping("/testResultError") public Test testResultError() { Test test = null; test.setName("简略点,抛个空指针吧"); return test; } @Data static class Test { private String name; private Integer age; private String remark; }}
咱们先看看这是调用返回的后果,能够看到,因为咱们对后果进行了对立封装,将错误信息放到了data外面。 但显然,status显示true,后盾都空指针了,这显然不是咱们想要的后果。
{ "status": true, "code": "0000", "msg": "", "data": { "timestamp": "2021-12-22T06:24:19.332+00:00", "status": 500, "error": "Internal Server Error", "message": "", "path": "/testResultError" }}
贴一下控制台错误信息
笑小枫控制台- 2022-07-15 22:25:38 [http-nio-6666-exec-1] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root causejava.lang.NullPointerException: null at com.maple.controller.TestResultController.testResultError(TestResultController.java:19) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ...
对立异样解决配置
这里应用了一个异样编码的枚举类ErrorCode.java
,在config.bean
包下创立,代码如下
package com.maple.demo.config.bean;import lombok.AllArgsConstructor;import lombok.Getter;/** * 对立异样信息枚举类 * * @author 笑小枫 * @date 2022/07/15 */@AllArgsConstructor@Getterpublic enum ErrorCode { /** * 异样信息 */ PARAM_ERROR("9001", "申请参数有误,请重试"), /** * 抛出此异样码,请从新在ErrorMsg定义msg */ COMMON_ERROR("9998", "笑小枫太懒,竟然没有定义异样起因"), OTHER_ERROR("9999", "未知异样,请分割笑小枫:https://www.xiaoxiaofeng.site"); private final String code; private final String msg;}
接下来咱们开始表演,在config目录下创立一个配置类ExceptionAdvice.java
,配置一下对异样拦挡解决,代码如下
package com.maple.demo.config;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.util.ResultJson;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;/** * 异样信息对立解决 * * @author 笑小枫 * @date 2022/07/15 */@Slf4j@RestControllerAdvicepublic class ExceptionAdvice { /** * 零碎异样. * * @param e 异样信息 * @return R */ @ExceptionHandler(Exception.class) public ResultJson exception(Exception e) { log.error("零碎异样信息 ex={}", e.getMessage(), e); // 未知异样对立抛出9999 return new ResultJson(ErrorCode.OTHER_ERROR.getCode(), ErrorCode.OTHER_ERROR.getMsg()); }}
咱们再看一下这个时候返回的后果,显然,这个后果咱们就能够承受了。程序中尽量避免呈现空指针哈,这里只是模仿...
{ "status": false, "code": "9999", "msg": "未知异样,请分割笑小枫:https://www.xiaoxiaofeng.site", "data": null}
自定义异样的解决
刚刚对对立异样做了解决,那像咱们自定义的异样怎么解决呢?
首先咱们创立一个自定义异样,咱们在config包下创立一个新的package吧,命名为exception,简略粗犷
而后先创立一个BaseException的自定义异样,而后不同的小类的异样再继承BaseException异样。 这样咱们能够间接拦挡BaseException异样就能够了。
BaseException异样这里取名为MapleBaseException.java
ps.Maple枫叶的意思;本项目名称亦为maple-demo
代码如下
package com.maple.demo.config.exception;import com.maple.demo.config.bean.ErrorCode;import lombok.Data;import lombok.EqualsAndHashCode;/** * 自定义异样-Base父类,细化的自定义异样,应该继承此类 * 对立异样解决时,会依据此异样类型做判断,返回后果时,如果是自定义异样主动解析code和errorMsg返回 * * @author 笑小枫 * @date 2022/07/15 */@EqualsAndHashCode(callSuper = true)@Datapublic class MapleBaseException extends RuntimeException { private final String code; private final String errorMsg; public MapleBaseException(String code, String errorMsg) { super(errorMsg); this.code = code; this.errorMsg = errorMsg; } public MapleBaseException(ErrorCode code) { super(code.getMsg()); this.code = code.getCode(); this.errorMsg = code.getMsg(); } public MapleBaseException(ErrorCode code, String errorMsg) { super(errorMsg); this.code = code.getCode(); this.errorMsg = errorMsg; }}
而后再定义一个校验的自定义异样(MapleCheckException.java
),继承MapleBaseException.java
,代码如下
package com.maple.demo.config.exception;import com.maple.demo.config.bean.ErrorCode;/** * 检测后果不统一时,抛出此异样 * * @author 笑小枫 * @date 2022/07/15 */public class MapleCheckException extends MapleBaseException { public MapleCheckException(String code, String errorMsg) { super(code, errorMsg); } public MapleCheckException(ErrorCode code) { super(code); } public MapleCheckException(ErrorCode code, String errorMsg) { super(code, errorMsg); }}
调整一下咱们的异样拦挡配置类,增加对咱们自定义异样的拦挡
/** * 自定义异样解决 * * @param e 异样信息 * @return 返回后果 */ @ExceptionHandler(MapleBaseException.class) public ResultJson mapleBaseException(MapleBaseException e) { log.error("自定义异样信息 ex={}", e.getMessage(), e); return new ResultJson(e.getCode(), e.getErrorMsg()); }
残缺代码如下
留神Exception异样拦挡下面的@Order(99)
,因为咱们自定义异样也属于Exception异样,所以应用Order执行时往后排。
package com.maple.demo.config;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.exception.MapleBaseException;import com.maple.demo.util.ResultJson;import lombok.extern.slf4j.Slf4j;import org.springframework.core.annotation.Order;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;/** * 异样信息对立解决 * * @author 笑小枫 * @date 2022/07/15 */@Slf4j@RestControllerAdvicepublic class ExceptionAdvice { /** * 自定义异样解决 * * @param e 异样信息 * @return 返回后果 */ @ExceptionHandler(MapleBaseException.class) public ResultJson mapleBaseException(MapleBaseException e) { log.error("自定义异样信息 ex={}", e.getMessage(), e); return new ResultJson(e.getCode(), e.getErrorMsg()); } /** * 零碎异样. * * @param e 异样信息 * @return R */ @ExceptionHandler(Exception.class) @Order(99) public ResultJson exception(Exception e) { log.error("零碎异样信息 ex={}", e.getMessage(), e); // 未知异样对立抛出9999 return new ResultJson(ErrorCode.OTHER_ERROR.getCode(), ErrorCode.OTHER_ERROR.getMsg()); }}
咱们再模仿一下抛出自定义异样
在TestErrorResultController.java
增加新的接口testMapleError
@GetMapping("/testMapleError") public Test testMapleError() { Test test = new Test(); test.setName("笑小枫"); if (test.getAge() == null) { throw new MapleCheckException(ErrorCode.COMMON_ERROR); } return test; }
残缺代码如下
package com.maple.demo.controller;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.exception.MapleCheckException;import lombok.Data;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @author 笑小枫 * @date 2022/07/15 */@RestController@RequiredArgsConstructor@RequestMapping("/example")public class TestErrorResultController { /** * 模拟系统空指针异样 */ @GetMapping("/testResultError") public Test testResultError() { Test test = null; test.setName("简略点,抛个空指针吧"); return test; } /** * 模仿自定义异样 */ @GetMapping("/testMapleError") public Test testMapleError() { Test test = new Test(); test.setName("笑小枫"); if (test.getAge() == null) { throw new MapleCheckException(ErrorCode.COMMON_ERROR); } return test; } @Data static class Test { private String name; private Integer age; private String remark; }}
最初,咱们来看一下后果
{ "status": false, "code": "9998", "msg": "笑小枫太懒,竟然没有定义异样起因", "data": null}
贴一下控制台异样信息
笑小枫控制台- 2022-07-15 22:38:26 [http-nio-6666-exec-2] ERROR com.maple.config.ExceptionAdvice - 自定义异样信息 ex=笑小枫太懒,竟然没有定义异样起因com.maple.config.exception.MapleCheckException: 笑小枫太懒,竟然没有定义异样起因 at com.maple.controller.TestResultController.testResultError(TestResultController.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ...
@Validated对入参校验的异样解决
下面的说的@Validated对入参校验的异样解决,零碎抛出异样格局太丑,这里做了简略优化。这里简略贴一下代码,这里不做具体概述,前面用到的中央再具体介绍。
/** * 参数校验异样解决 * * @param e 异样信息 * @return 返回后果 */ @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class}) public ResultJson validException(MethodArgumentNotValidException e) { log.error("参数校验异样信息 ex={}", e.getMessage(), e); BindingResult result = e.getBindingResult(); StringBuilder stringBuilder = new StringBuilder(); if (result.hasErrors()) { List<ObjectError> errors = result.getAllErrors(); errors.forEach(p -> { FieldError fieldError = (FieldError) p; stringBuilder.append(fieldError.getDefaultMessage()); }); } return new ResultJson(ErrorCode.PARAM_ERROR.getCode(), stringBuilder.toString()); }
残缺代码如下
package com.maple.demo.config;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.exception.MapleBaseException;import com.maple.demo.util.ResultJson;import lombok.extern.slf4j.Slf4j;import org.springframework.core.annotation.Order;import org.springframework.validation.BindException;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.validation.ObjectError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.List;/** * 异样信息对立解决 * * @author 笑小枫 * @date 2022/07/15 */@Slf4j@RestControllerAdvicepublic class ExceptionAdvice { /** * 自定义异样解决 * * @param e 异样信息 * @return 返回后果 */ @ExceptionHandler(MapleBaseException.class) public ResultJson mapleBaseException(MapleBaseException e) { log.error("自定义异样信息 ex={}", e.getMessage(), e); return new ResultJson(e.getCode(), e.getErrorMsg()); } /** * 参数校验异样解决 * * @param e 异样信息 * @return 返回后果 */ @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class}) public ResultJson validException(MethodArgumentNotValidException e) { log.error("参数校验异样信息 ex={}", e.getMessage(), e); BindingResult result = e.getBindingResult(); StringBuilder stringBuilder = new StringBuilder(); if (result.hasErrors()) { List<ObjectError> errors = result.getAllErrors(); errors.forEach(p -> { FieldError fieldError = (FieldError) p; stringBuilder.append(fieldError.getDefaultMessage()); }); } return new ResultJson(ErrorCode.PARAM_ERROR.getCode(), stringBuilder.toString()); } /** * 零碎异样. * * @param e 异样信息 * @return R */ @ExceptionHandler(Exception.class) @Order(99) public ResultJson exception(Exception e) { log.error("零碎异样信息 ex={}", e.getMessage(), e); // 未知异样对立抛出9999 return new ResultJson(ErrorCode.OTHER_ERROR.getCode(), ErrorCode.OTHER_ERROR.getMsg()); }}
小结
好啦,本文就到这里了,咱们简略的总结一下,次要介绍了以下内容
- 对立异样信息处理
- 自定义异样创立及应用
- 对立异样拦挡自定义异样
- 对立异样拦挡Spring的@Validated参数校验抛出的异样
本文源码:https://github.com/hack-feng/maple-demo