• springboot实战(九)之全局异常捕获&异常统一处理


    目录

    序言:

    1.环境:

    2.全局异常处理:

    2.1配置全局捕获异常

    2.2创建统一返回类、异常码

    2.3创建自定义异常类

    2.4测试

    2.5扩展


    序言:

    1.生产环境中为了前后端更加友好的交互,我们需要对异常做标准化处理,向前端返回约定好的的状态码和异常信息

    2.生产环境中为了更快的定位到程序异常,解决问题,我们需要对异常进行处理,处理成符合我们接受习惯的,更加友好的异常日志信息。

    1.环境:

    版本:spring boot:2.7.15

    jdk:1.8

    2.全局异常处理

    全局异常处理springboot项目给我们提供了增强类@RestControllerAdvice供我们使用

    2.1配置全局捕获异常

    异常捕获通过注解@ExceptionHandler

    1. package com.iterge.iterge_pre.config;
    2. import com.iterge.iterge_pre.entity.Response;
    3. import com.iterge.iterge_pre.exception.BizException;
    4. import com.iterge.iterge_pre.exception.ErrorCode;
    5. import lombok.extern.slf4j.Slf4j;
    6. import org.springframework.web.bind.annotation.ExceptionHandler;
    7. import org.springframework.web.bind.annotation.RestControllerAdvice;
    8. import javax.servlet.http.HttpServletRequest;
    9. /**
    10. * @author liuph
    11. * @date 2023/9/27 15:37:21
    12. */
    13. @Slf4j
    14. @RestControllerAdvice
    15. public class GlobalExceptionConfig {
    16. @ExceptionHandler(Throwable.class)
    17. public Response handleException(Throwable e, HttpServletRequest request) {
    18. log.error("执行异常,异常信息:接口:{},信息:{}",request.getRequestURI(),e.getMessage());
    19. return Response.of(new BizException(ErrorCode.UNKNOWN_EXCEPTION, e.getMessage()));
    20. }
    21. //自定义异常
    22. @ExceptionHandler(BizException.class)
    23. public Response bizHandleException(BizException e, HttpServletRequest request) {
    24. log.error("执行异常,异常信息:接口:{},信息:{}",request.getRequestURI(),e.getMsg());
    25. return Response.of(e);
    26. }
    27. }

    2.2创建统一返回类、异常码

    1. package com.iterge.iterge_pre.entity;
    2. import com.fasterxml.jackson.annotation.JsonAlias;
    3. import com.fasterxml.jackson.annotation.JsonProperty;
    4. import com.iterge.iterge_pre.exception.BizException;
    5. import lombok.Data;
    6. /**
    7. * @author liuph
    8. * @date 2023/9/27 15:34:20
    9. */
    10. @Data
    11. public class Response {
    12. /**
    13. * 成功返回ok, 异常返回错误原因。
    14. */
    15. /**
    16. * 返回的协议版本号
    17. */
    18. private int version = 0;
    19. /**
    20. * 返回的状态码
    21. */
    22. private int status = 0;
    23. /**
    24. * 错误信息
    25. */
    26. @JsonProperty("err_msg")
    27. @JsonAlias("errMsg")
    28. private String errMsg = "";
    29. /**
    30. * 错误信息
    31. */
    32. @JsonProperty("error_msg")
    33. @JsonAlias("errorMsg")
    34. private String errorMsg = "";
    35. /**
    36. * 服务器时间戳
    37. */
    38. private long ts;
    39. /**
    40. * 返回的数据
    41. */
    42. private T data;
    43. public Response() {
    44. ts = System.currentTimeMillis();
    45. }
    46. public static Response ok() {
    47. return ok(null);
    48. }
    49. public static Response ok(T data) {
    50. return ok(0, data);
    51. }
    52. public static Response ok(int version, T data) {
    53. return ok(version, System.currentTimeMillis(), data);
    54. }
    55. public static Response ok(int version, long ts, T data) {
    56. return ok(0, version, ts, "ok", data);
    57. }
    58. public static Response ok(int status, int version, long ts, String msg, T data) {
    59. Response resp = new Response<>();
    60. resp.setData(data);
    61. if (null != msg)
    62. resp.setErrMsg(msg);
    63. resp.setVersion(version);
    64. resp.setTs(ts);
    65. return resp;
    66. }
    67. public static Response of(BizException e) {
    68. Response response = new Response<>();
    69. response.setStatus(e.getCode());
    70. response.setErrMsg(e.getMsg());
    71. response.setErrorMsg(e.getMessage());
    72. response.setData(null);
    73. return response;
    74. }
    75. }

    1. package com.iterge.iterge_pre.exception;
    2. /**
    3. * @author liuph
    4. * @date 2023/9/27 15:43:37
    5. */
    6. public class ErrorCode {
    7. public static final ErrorCode OK = define(0, "ok");
    8. public static final ErrorCode PARAM_INVALID = define(-1, "参数错误");
    9. public static final ErrorCode DB_EXCEPTION = define(-2, "数据库错误");
    10. public static final ErrorCode REDIS_EXCEPTION = define(-3, "Redis错误");
    11. public static final ErrorCode MEMCACHE_EXCEPTION = define(-4, "Memcache错误");
    12. public static final ErrorCode MQ_EXCEPTION = define(-5, "MQ错误");
    13. public static final ErrorCode RPC_EXCEPTION = define(-6, "RPC调用错误");
    14. public static final ErrorCode CONFIG_EXCEPTION = define(-7, "配置错误");
    15. public static final ErrorCode DATA_NOT_EXIST = define(-20, "数据不存在");
    16. public static final ErrorCode AUTHENTICATION_FAILED = define(-41, "认证失败");
    17. public static final ErrorCode PERMISSION_DENIED = define(-42, "权限不足");
    18. public static final ErrorCode BUSINESS_EXCEPTION = define(-50, "业务异常");
    19. public static final ErrorCode UNKNOWN_EXCEPTION = define(-100, "未知异常");
    20. private int code;
    21. private String msg;
    22. protected ErrorCode() {
    23. this.code = 0;
    24. this.msg = null;
    25. }
    26. private ErrorCode(int code, String msg) {
    27. this.code = code;
    28. this.msg = msg;
    29. }
    30. public static ErrorCode define(int code, String msg) {
    31. return new ErrorCode(code, msg);
    32. }
    33. public static ErrorCode define(int code) {
    34. return define(code, (String)null);
    35. }
    36. public int getCode() {
    37. return this.code;
    38. }
    39. public String getMsg() {
    40. return this.msg;
    41. }
    42. public boolean equals(Object o) {
    43. if (this == o) {
    44. return true;
    45. } else if (o != null && this.getClass() == o.getClass()) {
    46. ErrorCode errorCode = (ErrorCode)o;
    47. return this.code == errorCode.code;
    48. } else {
    49. return false;
    50. }
    51. }
    52. }

    2.3创建自定义异常类

    1. package com.iterge.iterge_pre.exception;
    2. /**
    3. * @author liuph
    4. * @date 2023/9/27 15:43:37
    5. */
    6. public class ErrorCode {
    7. public static final ErrorCode OK = define(0, "ok");
    8. public static final ErrorCode PARAM_INVALID = define(-1, "参数错误");
    9. public static final ErrorCode DB_EXCEPTION = define(-2, "数据库错误");
    10. public static final ErrorCode REDIS_EXCEPTION = define(-3, "Redis错误");
    11. public static final ErrorCode MEMCACHE_EXCEPTION = define(-4, "Memcache错误");
    12. public static final ErrorCode MQ_EXCEPTION = define(-5, "MQ错误");
    13. public static final ErrorCode RPC_EXCEPTION = define(-6, "RPC调用错误");
    14. public static final ErrorCode CONFIG_EXCEPTION = define(-7, "配置错误");
    15. public static final ErrorCode DATA_NOT_EXIST = define(-20, "数据不存在");
    16. public static final ErrorCode AUTHENTICATION_FAILED = define(-41, "认证失败");
    17. public static final ErrorCode PERMISSION_DENIED = define(-42, "权限不足");
    18. public static final ErrorCode BUSINESS_EXCEPTION = define(-50, "业务异常");
    19. public static final ErrorCode UNKNOWN_EXCEPTION = define(-100, "未知异常");
    20. private int code;
    21. private String msg;
    22. protected ErrorCode() {
    23. this.code = 0;
    24. this.msg = null;
    25. }
    26. private ErrorCode(int code, String msg) {
    27. this.code = code;
    28. this.msg = msg;
    29. }
    30. public static ErrorCode define(int code, String msg) {
    31. return new ErrorCode(code, msg);
    32. }
    33. public static ErrorCode define(int code) {
    34. return define(code, (String)null);
    35. }
    36. public int getCode() {
    37. return this.code;
    38. }
    39. public String getMsg() {
    40. return this.msg;
    41. }
    42. public boolean equals(Object o) {
    43. if (this == o) {
    44. return true;
    45. } else if (o != null && this.getClass() == o.getClass()) {
    46. ErrorCode errorCode = (ErrorCode)o;
    47. return this.code == errorCode.code;
    48. } else {
    49. return false;
    50. }
    51. }
    52. }

    2.4测试

    controller中添加测试方式

    1. @GetMapping("test1/{id}")
    2. public Response getUser(@PathVariable("id") Integer id){
    3. if(id != 1){
    4. throw new BizException(ErrorCode.PARAM_INVALID);
    5. }
    6. log.info("成功");
    7. return Response.ok();
    8. }

    以上代码的逻辑是:当我们的入参id!=1的时候抛出我们的自定义异常BizException,并通过全局异常类GlobalExceptionConfig捕获类进行捕获,捕获异常后,进行对程序员比较友好的日志打印,最后通过统一返回类Response进行接口结果返回

    2.5扩展

    如果业务上有别的异常需要单独处理,则可以在GlobalExceptionConfig类中使@ExceptionHandler注解进行新增。例如下面的空指针异常

    1. //空指针异常
    2. @ExceptionHandler(NullPointerException.class)
    3. public Response nullPointerHandleException(NullPointerException e, HttpServletRequest request) {
    4. log.error("空指针异常:接口:{},信息:{}",request.getRequestURI(),e.getMessage());
    5. return Response.of(new BizException(ErrorCode.BUSINESS_EXCEPTION));
    6. }

  • 相关阅读:
    无聊的一篇博客(如何通过路由器登陆页对固定机器进行网速干扰,如何帮熊孩子戒网瘾)
    C 基本语法
    双数组字典树 (Double-array Trie) 实现原理 -- 代码 + 图文,看不懂你来打我
    Python电网静态和准静态分析及自动化优化
    JAVA高并发——线程池
    流量3-------3
    2. Java 对象和类
    微服务Redis分布式锁配置成注解使用(AOP)
    在playfab server上部署unreal linux server
    若依框架的使用
  • 原文地址:https://blog.csdn.net/it_erge/article/details/133356369