SpringBoot全局异常统一处理

小咪咪 2023-07-18 02:39 67阅读 0赞

目标:

对运行时发生的异常进行统一处理

处理自定义异常

  1. Validator统一异常封装

Assert的异常统一封装

一:定义异常统一返回的格式规范:

  1. import com.techsun.industry.common.enums.ResultCode;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. import org.apache.commons.lang3.StringUtils;
  7. @Builder
  8. @AllArgsConstructor
  9. @NoArgsConstructor
  10. @Data
  11. public class ErrorResult {
  12. /**
  13. * 异常状态码
  14. */
  15. private Integer status;
  16. /**
  17. * 用户看得见的异常,例如 用户名重复!!,
  18. */
  19. private String message;
  20. /**
  21. * 异常的名字
  22. */
  23. private String exception;
  24. /**
  25. * 异常堆栈信息
  26. */
  27. //private String errors;
  28. /**
  29. * 对异常提示语进行封装
  30. */
  31. public static ErrorResult fail(ResultCode resultCode, Throwable e, String message) {
  32. ErrorResult result = ErrorResult.fail(resultCode, e);
  33. if(StringUtils.isNotBlank(message)){
  34. result.setMessage(message);
  35. }
  36. return result;
  37. }
  38. /**
  39. * 对异常枚举进行封装
  40. */
  41. public static ErrorResult fail(ResultCode resultCode, Throwable e) {
  42. ErrorResult result = new ErrorResult();
  43. result.setMessage(resultCode.message());
  44. result.setStatus(resultCode.code());
  45. result.setException(e.getClass().getName());
  46. //result.setErrors(Throwables.getStackTraceAsString(e));
  47. return result;
  48. }
  49. }

二:自定义异常用来处理业务逻辑中的异常情况

  1. import com.techsun.industry.common.enums.ResultCode;
  2. import lombok.Data;
  3. /**
  4. * 自定义异常
  5. */
  6. @Data
  7. public class BusinessException extends RuntimeException{
  8. public Integer code;
  9. public String message;
  10. public BusinessException(ResultCode resultCode) {
  11. this.code = resultCode.code();
  12. this.message = resultCode.message();
  13. }
  14. }

三:编写全局异常处理类

  1. package com.*.*.config.aspect;
  2. import com.techsun.industry.common.base.response.ErrorResult;
  3. import com.techsun.industry.common.enums.ResultCode;
  4. import com.techsun.industry.common.exception.BusinessException;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.validation.FieldError;
  8. import org.springframework.web.bind.MethodArgumentNotValidException;
  9. import org.springframework.web.bind.annotation.*;
  10. import javax.servlet.http.HttpServletRequest;
  11. import java.util.List;
  12. @RestControllerAdvice
  13. @Slf4j
  14. /**
  15. * 全局异常处理
  16. */
  17. public class GlobalExceptionHandler {
  18. /**
  19. * 处理运行时异常
  20. */
  21. @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  22. @ExceptionHandler(Throwable.class)
  23. public ErrorResult handleThrowable(Throwable e, HttpServletRequest request) {
  24. //TODO 运行时异常,可以在这里记录,用于发异常邮件通知
  25. ErrorResult error =ErrorResult.fail(ResultCode.SYSTEM_ERROR, e);
  26. log.error("URL:{} ,系统异常: ",request.getRequestURI(), e);
  27. return error;
  28. }
  29. /**
  30. * 处理自定义异常
  31. */
  32. @ExceptionHandler(BusinessException.class)
  33. public ErrorResult handleBusinessException(BusinessException e, HttpServletRequest request) {
  34. ErrorResult error = ErrorResult.builder().status(e.code)
  35. .message(e.message)
  36. .exception(e.getClass().getName())
  37. .build();
  38. log.warn("URL:{} ,业务异常:{}", request.getRequestURI(),error);
  39. return error;
  40. }
  41. /**
  42. * validator 统一异常封装
  43. */
  44. @ResponseStatus(HttpStatus.BAD_REQUEST)
  45. @ExceptionHandler(MethodArgumentNotValidException.class)
  46. public ErrorResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
  47. String msgs = this.handle(e.getBindingResult().getFieldErrors());
  48. ErrorResult error = ErrorResult.fail(ResultCode.PARAM_IS_INVALID, e, msgs);
  49. log.warn("URL:{} ,参数校验异常:{}", request.getRequestURI(),msgs);
  50. return error;
  51. }
  52. private String handle(List<FieldError> fieldErrors) {
  53. StringBuilder sb = new StringBuilder();
  54. for (FieldError obj : fieldErrors) {
  55. sb.append(obj.getField());
  56. sb.append("=[");
  57. sb.append(obj.getDefaultMessage());
  58. sb.append("] ");
  59. }
  60. return sb.toString();
  61. }
  62. /**
  63. * Assert的异常统一封装
  64. */
  65. @ExceptionHandler(IllegalArgumentException.class)
  66. public ErrorResult illegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
  67. ErrorResult error = ErrorResult.builder().status(4000)
  68. .message(e.getMessage())
  69. .exception(e.getClass().getName())
  70. .build();
  71. log.warn("URL:{} ,业务校验异常:{}", request.getRequestURI(),e);
  72. return error;
  73. }
  74. }

对应ResultCode枚举类:

  1. public enum ResultCode {
  2. /* 成功状态码 */
  3. SUCCESS(200, "成功"),
  4. /* 系统500错误*/
  5. SYSTEM_ERROR(10000, "系统异常,请稍后重试"),
  6. /* 参数错误:10001-19999 */
  7. PARAM_IS_INVALID(10001, "参数无效"),
  8. /* 用户错误:20001-29999*/
  9. USER_HAS_EXISTED(20001, "用户已存在"),
  10. USER_LOGIN_FAIL(20002,"账号或密码错误"),
  11. USER_HAS_EXIST(20003,"账号已存在"),
  12. USER_NOT_EXIST(20003,"用户不存在,请重新登录"),
  13. /* 认证失败错误:30001-39999*/
  14. NO_TOKEN(30001,"无token,请重新登录"),
  15. TOKEN_OUT_TIME(30002,"token超时,请重新登录"),
  16. TOKEN_ILLEGAL(30003,"token 认证失败"),
  17. /* 文件失败错误:40001-49999*/
  18. EXCEL_NO_SHEET(40001,"Excel无Sheet");
  19. private Integer code;
  20. private String message;
  21. ResultCode(Integer code, String message) {
  22. this.code = code;
  23. this.message = message;
  24. }
  25. public Integer code() {
  26. return this.code;
  27. }
  28. public String message() {
  29. return this.message;
  30. }
  31. public static String getMessage(String name) {
  32. for (ResultCode item : ResultCode.values()) {
  33. if (item.name().equals(name)) {
  34. return item.message;
  35. }
  36. }
  37. return name;
  38. }
  39. public static Integer getCode(String name) {
  40. for (ResultCode item : ResultCode.values()) {
  41. if (item.name().equals(name)) {
  42. return item.code;
  43. }
  44. }
  45. return null;
  46. }
  47. @Override
  48. public String toString() {
  49. return this.name();
  50. }
  51. }

可根据实际情况将Code状态码进行划分。

我们可以参考下Http请求返回的状态码:

  1. 下面是常见的HTTP状态码:
  2. 200 - 请求成功
  3. 301 - 资源(网页等)被永久转移到其它URL
  4. 404 - 请求的资源(网页等)不存在
  5. 500 - 内部服务器错误

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0h1SGFvX0NTRE4_size_16_color_FFFFFF_t_70

我们可以参考这样的设计,这样的好处就把错误类型归类到某个区间内,如果区间不够,可以设计成4位数。

  1. #1000~1999 区间表示参数错误
  2. #2000~2999 区间表示用户错误
  3. #3000~3999 区间表示接口异常

这样前端开发人员在得到返回值后,根据状态码就可以知道,大概什么错误,再根据message相关的信息描述,可以快速定位。

现在可以进行测试了.

发表评论

表情:
评论列表 (有 0 条评论,67人围观)

还没有评论,来说两句吧...

相关阅读

    相关 springboot异常全局统一处理

    [个人博客][Link 1] 日常后端业务开发中,在提供接口服务时会遇到各种异常处理,通常涉及到参数校验异常、自定义异常以及一些不可预知的异常等等。下面就来说一下在sprin