SpringBoot业务开发 03、Springboot异常处理

2022-10-03 07:56:33

前言

本篇博客是SpringBoot处理异常的解决方案,若文章中出现相关问题,请指出!

所有博客文件目录索引:博客目录索引(持续更新)

一、Springboot处理异常的三种处理方式

1、在Controller上标注@ExceptionHandler异常。

2、全级别异常处理,通过实现HandlerExceptionResolver接口,接着重写方法,在该方法中处理所有的异常!

3、全局级别异常处理器:@ControllerAdvice+@ExceptionHandler,推荐使用这种方式!!!



二、介绍第三种方法(@ControllerAdvice+@ExceptionHandler)

2.1、全局捕捉异常处理的相关注解

现在对于异常处理普通方法使用@ControllerAdvice+@ExceptionHandler

介绍几个注解的含义:

  1. @ControllerAdvice:捕捉所有标注@Controller类抛出的异常。

  2. @ExceptionHandler:标记了使用 errorHandlerOverJson() 方法来处理 GlobalErrorInfoException 异常。通常用于指定拦截指定的异常。

  3. @RestControllerAdvice:该注解其实是由@ControllerAdvice@ResponseBody组成的,我们一般后台捕捉到异常时都会向前端返回json字符串,所有可以直接使用该注解来标注于类,而不用在每个方法上加@ResponseBody



2.2、响应码设计

image-20210722232408945

  • ErrorInfoInterface:错误码接口规范,得到code响应码,message响应描述。
  • CityErrorInfoEnumGlobalErrorInfoEnum:这两个都是枚举类,都继承了错误码接口规范,我们可以创建多个枚举类来表示不同的情况描述,这两个类一个表示城市错误信息,另一个表示去全局错误信息枚举类!!!

BaseErrorInfoInterface.java:错误码接口规范

/**
 * @author changlu
 * @date 2021/07/22 17:03
 **/publicinterfaceBaseErrorInfoInterface{/**
     * 得到错误码
     * @date 2021/07/22 17:04
     * @return java.lang.String
     */StringgetResultCode();/**
     * 得到错误信息
     * @date 2021/07/22 17:05
     * @return java.lang.String
     */StringgetResultMsg();}

commonInfoEnum.java:普通错误枚举类

publicenumCommonEnumimplementsBaseErrorInfoInterface{SUCCESS("200","成功"),BODY_NOT_MATCH("400","请求的数据格式不符"),SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"),OT_FOUND("404","未找到该资源!"),INTERNAL_SERVER_ERROR("500","服务器内部错误!"),SERVER_BUSY("503","服务器正忙,请稍后再试!"),NULLPOINTER_ERROR("1001","空指针异常");//错误码privateString resultCode;//描述信息privateString resultMsg;CommonEnum(String resultCode,String resultMsg){this.resultCode= resultCode;this.resultMsg= resultMsg;}@OverridepublicStringgetResultCode(){return resultCode;}@OverridepublicStringgetResultMsg(){return resultMsg;}}

之后我们若是出现了某种异常情况,可直接拿到对应的枚举实例,也就直接拿到了code与message。



2.3、结果响应类(最终返回给前端)

该类有三个值组成:codemessagedata,分别是响应码、描述信息以及data数据(是一个对象)。

最终通过转成JSON字符串形式返回给前端!

ResultBody.java

/**
 * @author changlu
 * @date 2021/07/22 17:15
 **/@DatapublicclassResultBody{/**
     * 响应码
     */privateString code;/**
     * 响应消息
     */privateString message;/**
     * 响应结果
     */privateObject result;publicResultBody(){}/**
     * 响应码与响应结果封装
     */publicResultBody(BaseErrorInfoInterface baseErrorInfoInterface){this.code= baseErrorInfoInterface.getResultCode();this.message= baseErrorInfoInterface.getResultMsg();}/**
     * 成功
     * @param data 数据
     * @return xyz.changlu.util.ResultBody
     */publicstaticResultBodysuccess(Object data){ResultBody resultBody=newResultBody(CommonEnum.SUCCESS);
        resultBody.setResult(data);return resultBody;}/**
     * 错误
     * @param baseErrorInfoInterface 枚举类
     * @return xyz.changlu.util.ResultBody
     */publicstaticResultBodyerror(BaseErrorInfoInterface baseErrorInfoInterface){ResultBody resultBody=newResultBody(baseErrorInfoInterface);
        resultBody.setResult(null);return resultBody;}/**
     * 错误
     * @param code 状态码
     * @param message 描述信息
     * @return xyz.changlu.util.ResultBody
     */publicstaticResultBodyerror(String code,String message){ResultBody resultBody=newResultBody();
        resultBody.setCode(code);
        resultBody.setMessage(message);
        resultBody.setResult(null);return resultBody;}}


2.4、核心:自定义异常类与全局异常捕捉类

自定义异常类:通常自定义异常类继承运行时异常RuntimeException,因为这一类异常是不会强制程序员写try-catch进行捕获的,所以我们可以定义一些来进行手动抛出,之后供全局异常进行捕捉,可设置多个。

全局异常捕捉类:该类用于捕捉@controller注解标注的类抛出的异常,包含自定义异常以及其他异常,我们都可以进行单独编写,一般就这两种。

自定义异常类

publicclassMsgExceptionextendsRuntimeException{/**
     * 错误代码
     */privateString errorCode;/**
     * 错误信息
     */privateString errorMsg;publicMsgException(){}publicMsgException(String errorCode,String errorMsg){this.errorCode= errorCode;this.errorMsg= errorMsg;}publicMsgException(String message,String errorCode,String errorMsg){super(message);this.errorCode= errorCode;this.errorMsg= errorMsg;}//传入错误信息接口(如枚举类)publicMsgException(BaseErrorInfoInterface baseErrorInfoInterface,Throwable cause){super(baseErrorInfoInterface.getResultCode(), cause);this.errorCode= baseErrorInfoInterface.getResultCode();this.errorMsg= baseErrorInfoInterface.getResultMsg();}publicMsgException(Throwable cause,String errorCode,String errorMsg){super(errorCode, cause);this.errorCode= errorCode;this.errorMsg= errorMsg;}//set/get方法publicStringgetErrorCode(){return errorCode;}publicvoidsetErrorCode(String errorCode){this.errorCode= errorCode;}publicStringgetErrorMsg(){return errorMsg;}publicvoidsetErrorMsg(String errorMsg){this.errorMsg= errorMsg;}@OverridepublicsynchronizedThrowablefillInStackTrace(){returnsuper.fillInStackTrace();}}

全局异常捕捉类

当出现异常后,我们依旧会向前端进行响应返回数据!

/**
 * @author Administrator
 * @date 2021/07/22 17:27
 **/@RestControllerAdvicepublicclassMyExceptionHandler{privatestaticfinalLogger logger=LoggerFactory.getLogger(MyExceptionHandler.class);/**
     * 自定义的业务异常(自己向外抛出的异常)
     * @param HttpServletRequest servlet请求
     * @param ex 自定义抛出异常
     * @return xyz.changlu.util.ResultBody
     */@ExceptionHandler(value=MsgException.class)publicResultBodymsgExceptionHandler(HttpServletRequest request,MsgException ex){
        logger.error("自定义的业务异常拦截处理,原因是:"+ ex.getErrorMsg());returnResultBody.error(ex.getErrorCode(),ex.getErrorMsg());}/**
     * 空指针异常处理程序
     *
     * @param req 要求的事情
     * @param e   e
     * @return {@link ResultBody}
     */@ExceptionHandler(value=NullPointerException.class)publicResultBodyexceptionHandler(HttpServletRequest req,NullPointerException e){
        logger.error("空指针异常处理!原因是:", e.getMessage());returnResultBody.error(CommonEnum.NULLPOINTER_ERROR);}/**
     * 其他异常处理程序
     *
     * @param req 要求的事情
     * @param e   e
     * @return {@link ResultBody}
     */@ExceptionHandler(value=Exception.class)publicResultBodyexceptionHandler(HttpServletRequest req,Exception e){
        logger.error("其他异常处理程序!原因是:", e.getMessage());returnResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);}}


测试

我们来编写一些Controller来测试全局异常捕捉类是否能够捕捉到指定的异常:

/**
 * @author changlu
 * @date 2021/07/22 17:38
 **/@RestControllerpublicclassUserController{//测试自定义异常@PostMapping("/user")publicbooleanadd(User user){System.out.println("开始新增....");if(user.getName()==null){//抛出自定义异常thrownewMsgException("-1","用户姓名不能为空!");}returntrue;}//测试空指针异常@DeleteMapping("/user/{id}")publicbooleandelete(@PathVariable("id")Integer id){System.out.println("开始删除....");//抛出空指针String str=null;
        str.equals("123");returntrue;}//测试其他异常@PutMapping("/user/{id}")publicbooleanupdate(@PathVariable("id")Integer id,User user){System.out.println("开始更新....");//程序自己出错Integer.parseInt("abc123");returntrue;}@GetMapping("/user/{id}")publicResultBodyquery(@PathVariable("id")Integer id){System.out.println("开始查询....");returnResultBody.success(null);}}


参考文章

[1].Spring Boot HTTP over JSON 的错误码异常处理

[2].Spring 异常处理三种方式 @ExceptionHandler:包含原理介绍

[3].Springboot全局异常处理案例–@ControllerAdvice

我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
Q群:851968786 我们可以一起探讨学习
注明:转载可,需要附带上文章链接

  • 作者:长路 ㅤ   
  • 原文链接:https://changlu.blog.csdn.net/article/details/124479153
    更新时间:2022-10-03 07:56:33