• SpringBoot2.3.12.RELEASE优雅的全局异常处理(模板一)


    参考:https://www.cnblogs.com/xuwujing/p/10933082.html

    1、首先,需要引入maven依赖包,如下所示:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     5     <modelVersion>4.0.0</modelVersion>
     6     <parent>
     7         <groupId>org.springframework.boot</groupId>
     8         <artifactId>spring-boot-starter-parent</artifactId>
     9         <version>2.3.12.RELEASE</version>
    10         <relativePath /> <!-- lookup parent from repository -->
    11     </parent>
    12     <groupId>com.bie</groupId>
    13     <artifactId>SpringbootException</artifactId>
    14     <version>0.0.1-SNAPSHOT</version>
    15     <name>SpringbootException</name>
    16     <description>Demo project for Spring Boot</description>
    17 
    18     <properties>
    19         <java.version>1.8</java.version>
    20     </properties>
    21 
    22     <dependencies>
    23         <!-- 引入springboot web模块 -->
    24         <dependency>
    25             <groupId>org.springframework.boot</groupId>
    26             <artifactId>spring-boot-starter-web</artifactId>
    27         </dependency>
    28         <!-- 引入fastjson的依赖 -->
    29         <dependency>
    30             <groupId>com.alibaba</groupId>
    31             <artifactId>fastjson</artifactId>
    32             <version>1.2.41</version>
    33         </dependency>
    34 
    35         <dependency>
    36             <groupId>org.springframework.boot</groupId>
    37             <artifactId>spring-boot-starter-test</artifactId>
    38             <scope>test</scope>
    39             <exclusions>
    40                 <exclusion>
    41                     <groupId>org.junit.vintage</groupId>
    42                     <artifactId>junit-vintage-engine</artifactId>
    43                 </exclusion>
    44             </exclusions>
    45         </dependency>
    46     </dependencies>
    47 
    48     <build>
    49         <plugins>
    50             <plugin>
    51                 <groupId>org.springframework.boot</groupId>
    52                 <artifactId>spring-boot-maven-plugin</artifactId>
    53             </plugin>
    54         </plugins>
    55     </build>
    56 
    57 </project>

      SpringBoot中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需再自定义一个方法,然后使用ExceptionHandler注解,在该注解的value属性里面,定义捕获异常的类型,即可对这些捕获的异常进行统一的处理。

    2、自定义基础接口类。

      首先定义一个基础的接口类,自定义的错误描述枚举类需实现该接口。

     1 package com.bie.enums;
     2 
     3 public interface BaseErrorInfoInterface {
     4 
     5     // 错误码
     6     public String getResultCode();
     7 
     8     // 错误描述
     9     public String getResultMsg();
    10 
    11 }

    3、自定义枚举类。

      然后我们这里在自定义一个枚举类,并实现该接口。而使用枚举类的好处是处理异常的时候,可以通过枚举类直接获取到错误码、错误描述,方便调用。

     1 package com.bie.enums;
     2 
     3 public enum CommonEnum implements BaseErrorInfoInterface {
     4 
     5     // 数据操作错误定义
     6     SUCCESS("200", "接口调用成功!"),
     7 
     8     BODY_NOT_MATCH("400", "请求的数据格式不符!"),
     9 
    10     SIGNATURE_NOT_MATCH("401", "请求的数字签名不匹配!"),
    11 
    12     NOT_FOUND("404", "未找到该资源!"),
    13 
    14     INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
    15 
    16     SERVER_BUSY("503", "服务器正忙,请稍后再试!");
    17 
    18     // 错误码
    19     private String resultCode;
    20 
    21     // 错误描述
    22     private String resultMsg;
    23 
    24     CommonEnum(String resultCode, String resultMsg) {
    25         this.resultCode = resultCode;
    26         this.resultMsg = resultMsg;
    27     }
    28 
    29     @Override
    30     public String getResultCode() {
    31         return resultCode;
    32     }
    33 
    34     @Override
    35     public String getResultMsg() {
    36         return resultMsg;
    37     }
    38 
    39 }

    4、自定义异常类。

      然后我们在来自定义一个异常类,用于处理我们发生的业务异常。

     1 package com.bie.exception;
     2 
     3 import com.bie.enums.BaseErrorInfoInterface;
     4 
     5 public class BizException extends RuntimeException {
     6 
     7     /**
     8      * 
     9      */
    10     private static final long serialVersionUID = -6329783845738305585L;
    11 
    12     // 错误码
    13     protected String errorCode;
    14     // 错误信息
    15     protected String errorMsg;
    16 
    17     public BizException() {
    18         super();
    19     }
    20 
    21     public BizException(BaseErrorInfoInterface errorInfoInterface) {
    22         super(errorInfoInterface.getResultCode());
    23         this.errorCode = errorInfoInterface.getResultCode();
    24         this.errorMsg = errorInfoInterface.getResultMsg();
    25     }
    26 
    27     public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
    28         super(errorInfoInterface.getResultCode(), cause);
    29         this.errorCode = errorInfoInterface.getResultCode();
    30         this.errorMsg = errorInfoInterface.getResultMsg();
    31     }
    32 
    33     public BizException(String errorMsg) {
    34         super(errorMsg);
    35         this.errorMsg = errorMsg;
    36     }
    37 
    38     public BizException(String errorCode, String errorMsg) {
    39         super(errorCode);
    40         this.errorCode = errorCode;
    41         this.errorMsg = errorMsg;
    42     }
    43 
    44     public BizException(String errorCode, String errorMsg, Throwable cause) {
    45         super(errorCode, cause);
    46         this.errorCode = errorCode;
    47         this.errorMsg = errorMsg;
    48     }
    49 
    50     public String getErrorCode() {
    51         return errorCode;
    52     }
    53 
    54     public void setErrorCode(String errorCode) {
    55         this.errorCode = errorCode;
    56     }
    57 
    58     public String getErrorMsg() {
    59         return errorMsg;
    60     }
    61 
    62     public void setErrorMsg(String errorMsg) {
    63         this.errorMsg = errorMsg;
    64     }
    65 
    66     public String getMessage() {
    67         return errorMsg;
    68     }
    69 
    70     @Override
    71     public Throwable fillInStackTrace() {
    72         return this;
    73     }
    74 
    75 }

    5、自定义数据格式。

      顺便这里我们定义一下数据的传输格式,作用主要用于返回给前端的数据格式。

      1 package com.bie.utils;
      2 
      3 import com.alibaba.fastjson.JSONObject;
      4 import com.bie.enums.BaseErrorInfoInterface;
      5 import com.bie.enums.CommonEnum;
      6 
      7 public class ResultBody {
      8 
      9     // 响应代码
     10     private String code;
     11 
     12     // 响应消息
     13     private String message;
     14 
     15     // 响应结果
     16     private Object result;
     17 
     18     public ResultBody() {
     19     }
     20 
     21     public ResultBody(BaseErrorInfoInterface errorInfo) {
     22         this.code = errorInfo.getResultCode();
     23         this.message = errorInfo.getResultMsg();
     24     }
     25 
     26     public String getCode() {
     27         return code;
     28     }
     29 
     30     public void setCode(String code) {
     31         this.code = code;
     32     }
     33 
     34     public String getMessage() {
     35         return message;
     36     }
     37 
     38     public void setMessage(String message) {
     39         this.message = message;
     40     }
     41 
     42     public Object getResult() {
     43         return result;
     44     }
     45 
     46     public void setResult(Object result) {
     47         this.result = result;
     48     }
     49 
     50     /**
     51      * 成功
     52      * 
     53      * @return
     54      */
     55     public static ResultBody success() {
     56         return success(null);
     57     }
     58 
     59     /**
     60      * 成功
     61      * 
     62      * @param data
     63      * @return
     64      */
     65     public static ResultBody success(Object data) {
     66         ResultBody rb = new ResultBody();
     67         rb.setCode(CommonEnum.SUCCESS.getResultCode());
     68         rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
     69         rb.setResult(data);
     70         return rb;
     71     }
     72 
     73     /**
     74      * 失败
     75      */
     76     public static ResultBody error(BaseErrorInfoInterface errorInfo) {
     77         ResultBody rb = new ResultBody();
     78         rb.setCode(errorInfo.getResultCode());
     79         rb.setMessage(errorInfo.getResultMsg());
     80         rb.setResult(null);
     81         return rb;
     82     }
     83 
     84     /**
     85      * 失败
     86      */
     87     public static ResultBody error(String code, String message) {
     88         ResultBody rb = new ResultBody();
     89         rb.setCode(code);
     90         rb.setMessage(message);
     91         rb.setResult(null);
     92         return rb;
     93     }
     94 
     95     /**
     96      * 失败
     97      */
     98     public static ResultBody error(String message) {
     99         ResultBody rb = new ResultBody();
    100         rb.setCode("-1");
    101         rb.setMessage(message);
    102         rb.setResult(null);
    103         return rb;
    104     }
    105 
    106     @Override
    107     public String toString() {
    108         return JSONObject.toJSONString(this);
    109     }
    110 
    111 }

    6、自定义全局异常处理类。

      最后我们再来编写一个自定义全局异常处理的类,可以用于处理各类异常。

     1 package com.bie.exception;
     2 
     3 import javax.servlet.http.HttpServletRequest;
     4 
     5 import org.slf4j.Logger;
     6 import org.slf4j.LoggerFactory;
     7 import org.springframework.web.bind.annotation.ControllerAdvice;
     8 import org.springframework.web.bind.annotation.ExceptionHandler;
     9 import org.springframework.web.bind.annotation.ResponseBody;
    10 
    11 import com.bie.enums.CommonEnum;
    12 import com.bie.utils.ResultBody;
    13 
    14 @ControllerAdvice
    15 public class GlobalExceptionHandler {
    16 
    17     private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    18 
    19     /**
    20      * 处理自定义的业务异常
    21      * 
    22      * @param req
    23      * @param e
    24      * @return
    25      */
    26     @ExceptionHandler(value = BizException.class)
    27     @ResponseBody
    28     public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {
    29         logger.error("发生业务异常!原因是:{}", e.getErrorMsg());
    30         return ResultBody.error(e.getErrorCode(), e.getErrorMsg());
    31     }
    32 
    33     /**
    34      * 处理空指针的异常
    35      * 
    36      * @param req
    37      * @param e
    38      * @return
    39      */
    40     @ExceptionHandler(value = NullPointerException.class)
    41     @ResponseBody
    42     public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
    43         logger.error("发生空指针异常!原因是:", e);
    44         return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
    45     }
    46 
    47     /**
    48      * 处理其他异常
    49      * 
    50      * @param req
    51      * @param e
    52      * @return
    53      */
    54     @ExceptionHandler(value = Exception.class)
    55     @ResponseBody
    56     public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
    57         logger.error("未知异常!原因是:", e);
    58         return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
    59     }
    60 
    61 }

    7、创建一个用户的实体类,如下所示:

     1 package com.bie.po;
     2 
     3 import java.io.Serializable;
     4 
     5 import com.alibaba.fastjson.JSONObject;
     6 
     7 public class User implements Serializable {
     8 
     9     /**
    10      * 
    11      */
    12     private static final long serialVersionUID = 1360679426784375558L;
    13     
    14     // 编号
    15     private int id;
    16     // 姓名 
    17     private String name;
    18     // 年龄
    19     private int age;
    20 
    21     public User() {
    22     }
    23 
    24     public int getId() {
    25         return id;
    26     }
    27 
    28     public void setId(int id) {
    29         this.id = id;
    30     }
    31 
    32     public String getName() {
    33         return name;
    34     }
    35 
    36     public void setName(String name) {
    37         this.name = name;
    38     }
    39 
    40     public int getAge() {
    41         return age;
    42     }
    43 
    44     public void setAge(int age) {
    45         this.age = age;
    46     }
    47 
    48     public String toString() {
    49         return JSONObject.toJSONString(this);
    50     }
    51 
    52 }

    8、Controller 控制层。

      控制层这边也比较简单,使用Restful风格实现的CRUD功能,主要是Restful风格的,根据请求方式get、post、put、delete,而请求路径是一个,主要根据请求方式来做区分操作。

     1 package com.bie.controller;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import org.springframework.web.bind.annotation.DeleteMapping;
     7 import org.springframework.web.bind.annotation.GetMapping;
     8 import org.springframework.web.bind.annotation.PostMapping;
     9 import org.springframework.web.bind.annotation.PutMapping;
    10 import org.springframework.web.bind.annotation.RequestBody;
    11 import org.springframework.web.bind.annotation.RequestMapping;
    12 import org.springframework.web.bind.annotation.RestController;
    13 
    14 import com.bie.exception.BizException;
    15 import com.bie.po.User;
    16 
    17 @RestController
    18 @RequestMapping(value = "/api")
    19 public class UserRestController {
    20 
    21     @PostMapping("/user")
    22     public boolean insert(@RequestBody User user) {
    23         System.out.println("开始新增...");
    24         // 如果姓名为空就手动抛出一个自定义的异常!
    25         if (user.getName() == null) {
    26             throw new BizException("-1", "用户姓名不能为空!");
    27         }
    28         return true;
    29     }
    30 
    31     @PutMapping("/user")
    32     public boolean update(@RequestBody User user) {
    33         System.out.println("开始更新...");
    34         // 这里故意造成一个空指针的异常,并且不进行处理
    35         String str = null;
    36         str.equals("111");
    37         return true;
    38     }
    39 
    40     @DeleteMapping("/user")
    41     public boolean delete(@RequestBody User user) {
    42         System.out.println("开始删除...");
    43         // 这里故意造成一个异常,并且不进行处理
    44         Integer.parseInt("abc123");
    45         return true;
    46     }
    47 
    48     @GetMapping("/user")
    49     public List<User> findByUser(User user) {
    50         System.out.println("开始查询...");
    51         List<User> userList = new ArrayList<>();
    52         User user2 = new User();
    53         user2.setId(1);
    54         user2.setName("xuwujing");
    55         user2.setAge(18);
    56         userList.add(user2);
    57         return userList;
    58     }
    59 
    60 }

    9、接口功能测试,使用postman进行测试,如下所示:

    9.1、首先进行查询,查看程序是否正常运行,使用GET 方式进行请求,如下所示:

    9.2、进行插入操作,使用POST方式进行请求,如下所示:

    9.3、进行修改操作,使用PUT方式进行请求,如下所示: 

    9.4、进行删除操作,使用DELETE方式进行请求,如下所示:
     

    10、整体思路解析,按照步骤操作,按道理来说,这个思路是很优秀的,那么下面来分析一下这个设计思路。

    10.1、在自己的方法中抛出自定义异常,而抛出的自定义异常是被全局异常类进行捕获处理的。

      对抛出的自定义异常,在全局异常处理类中进行处理,然后返回的信息,是封装到自定义数据格式类中的,这样返回给前端的数据格式,就可以根据自己的需求进行设计。

    10.2、而对于全局异常类中,可以定义捕获其他类型的异常。而在捕获其他异常之后,返回的数据封装到自定义数据格式里面,而对于其他异常而已直接使用定义的枚举类中来选择异常内容。

    虽然,这种设计不能说100%完美,但是设计的已经很优秀了,基本可以满足日常需求,赞一个。

  • 相关阅读:
    redisserver 双击闪退
    PHP QueryList采集器
    【ubuntu】配置国内源
    【ffmpeg基础知识】文件的删除和重命名
    【ffmpeg基础知识】打印视频meta信息
    Ubuntu下pkgconfig环境变量配置
    音视频基础知识
    【linux小技巧】返回上一个目录,vi默认显示行号,vi多窗口
    【ffmpeg基础知识】ffmpeg操作目录实现list
    【ffmpeg基础知识】日常日志
  • 原文地址:https://www.cnblogs.com/biehongli/p/14944622.html
Copyright © 2020-2023  润新知