• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

SpringBoot 全局异常拦截捕获处理

武飞扬头像
sh顺其自然
帮助1

个人学习用-搬运原文链接

1、需求

前后端分离项目中,后端通常是以json形式将数据返回给前端。此时,如果服务器内部出现异常,如何对内部异常处理后响应给前端呢?

2、实现方式

结合 @RestControllerAdvice@ExceptionHandler 来捕获绝大部分异常,然后通过自定义的全局数据返回对象统一返回Json形式给前端。
@RestControllerAdvice: 增强类;
@ExceptionHandler: 标注异常处理方法,包括异常类型。

3、具体步骤

3.1、自定义 全局数据返回对象

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;

/**
 * 接口返回数据格式
 */
@Data
@ApiModel(value = "接口返回对象", description = "接口返回对象")
public class Result<T> implements Serializable {
  /**
   * 状态码
   */
  private static final Integer HANDLE_OK = 200;
  private static final Integer CLIENT_NOT_FOUND_404 = 404;
  private static final Integer CLIENT_NO_AUTH_401 = 401;
  private static final Integer SERVER_ERROR_500 = 500;
  private static final Integer SERVER_NO_AUTH_510 = 200;

  private static final long serialVersionUID = 1L;

  /**
   * 成功标志
   */
  @ApiModelProperty(value = "成功标志")
  private boolean success = true;

  /**
   * 返回处理消息
   */
  @ApiModelProperty(value = "返回处理消息")
  private String message = "";

  /**
   * 返回代码(状态码)
   */
  @ApiModelProperty(value = "返回代码")
  private Integer code = 0;

  /**
   * 返回数据对象 data
   */
  @ApiModelProperty(value = "返回数据对象")
  private T result;

  /**
   * 时间戳
   */
  @ApiModelProperty(value = "时间戳")
  private long timestamp = System.currentTimeMillis();

  public Result() {
  }

  /**
   * 兼容VUE3版token失效不跳转登录页面
   * @param code
   * @param message
   */
  public Result(Integer code, String message) {
    this.code = code;
    this.message = message;
  }

  public Result<T> success(String message) {
    this.message = message;
    this.code = HANDLE_OK;
    this.success = true;
    return this;
  }

  public static <T> Result<T> ok() {
    Result<T> r = new Result<T>();
    r.setSuccess(true);
    r.setCode(HANDLE_OK);
    return r;
  }

  public static <T> Result<T> ok(String msg) {
    Result<T> r = new Result<T>();
    r.setSuccess(true);
    r.setCode(HANDLE_OK);
    r.setMessage(msg);
    r.setResult((T) msg);
    return r;
  }

  public static <T> Result<T> ok(T data) {
    Result<T> r = new Result<T>();
    r.setSuccess(true);
    r.setCode(HANDLE_OK);
    r.setResult(data);
    return r;
  }

  public static <T> Result<T> ok(String msg, T data) {
    Result<T> r = new Result<T>();
    r.setSuccess(true);
    r.setCode(HANDLE_OK);
    r.setMessage(msg);
    r.setResult(data);
    return r;
  }

  public static <T> Result<T> error(String msg) {
    return error(SERVER_ERROR_500, msg);
  }
  
  public static <T> Result<T> error(String msg, T data) {
    Result<T> r = new Result<T>();
    r.setSuccess(false);
    r.setCode(SERVER_ERROR_500);
    r.setMessage(msg);
    r.setResult(data);
    return r;
  }

  public static <T> Result<T> error(int code, String msg) {
    Result<T> r = new Result<T>();
    r.setCode(code);
    r.setMessage(msg);
    r.setSuccess(false);
    return r;
  }

  public Result<T> error500(String message) {
    this.message = message;
    this.code = SERVER_ERROR_500;
    this.success = false;
    return this;
  }

  /**
   * 无权限访问返回结果
   */
  public static <T> Result<T> noauth(String msg) {
    return error(SERVER_NO_AUTH_510, msg);
  }
}
学新通

3.2、自定义 全局异常捕获处理类

1. 清楚具体异常类型时

在类上,通过 @RestControllerAdvice(annotations = Controller.class) 注解标注全局异常处理类,指定处理带有@Controller注解的类,也就是controller层的所有方法。
在方法上,通过 @ExceptionHandler({ArithmeticException.class}) 标注异常处理方法以及方法所处理的异常类型。

@Slf4j
@RestControllerAdvice
public class ExceptionsHandler {

    @ExceptionHandler({ArithmeticException.class})
    public Result<String> arithmeticException(ArithmeticException ex) {
        log.error("除数不能为0:{} ", ex.getMessage(), ex);
        return Result.error(400, "除数不能为0");
    }
}

2. 不清楚具体异常类型时,直接捕获异常的公共类 Exception

@ControllerAdvice(annotations = Controller.class)
public class ExceptionAdvice {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);

    @ExceptionHandler(Exception.class)
    public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 打印异常日志
        logger.error(e.getMessage());
        StackTraceElement[] stackTrace = e.getStackTrace();
        for (StackTraceElement element : stackTrace) {
            logger.error(element.toString());
        }

        // 返回处理结果,要判断异常发生的请求是普通请求(返回页面),还是异步请求(返回json数据)
        String xRequestedWith = request.getHeader("x-requested-with");
        // 异步请求
        if (xRequestedWith.equals("XMLHttpRequest")) {
            response.setContentType("application/plain;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write(CommunityUtil.getJSONString(1, "服务器发生异常!"));
        } else {
            response.sendRedirect(request.getContextPath()   "/error");
        }
    }
}
学新通

3.3、编写测试方法

编写测试方法(会出现异常的方法)

@RestController
@RequestMapping("/exception")
public class ExceptionTestController {

    @GetMapping("/test")
    public Result<Integer> testException(int num) {
        int res = 23 / num;
        return Result.ok(res);
    }
}

3.4、测试

异步请求: 返回json数据
学新通
普通方法: 返回页面
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbhehj
系列文章
更多 icon
同类精品
更多 icon
继续加载