Spring Boot2.x.x 全局错误处理

Spring Boot2.x.x 全局错误+自定义Result 结果处理

插件安装

复制代码
  <dependency>
    <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.20</version> // 可能版本不同插件兼容也会存在差异
  </dependency>

GlobalExceptionHandler.java

js 复制代码
package com.sky.handler;

import com.sky.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.server.ResponseStatusException;

// 全局异常捕获与处理

/**
 * @RestControllerAdvice Spring 提供的全局异常处理注解。
 * 它等价于 @ControllerAdvice + @ResponseBody,意味着:
 * 这个类会扫描整个项目中所有 Controller 抛出的异常。
 * 返回的结果会被自动序列化成 JSON(适合 REST API)。
 * @Slf4j Lombok 注解,自动生成一个 log 对象,用于日志打印。
 */
@RestControllerAdvice
@Slf4j

/**
 * 用户访问你的 API,例如 /api/data。
 * Controller 或 Service 里抛出异常:
 * 如果是 ResponseStatusException,就走第一个处理方法。
 * 如果是其他异常(比如 NullPointerException),就走第二个方法。
 * 全局异常处理器把异常转换成 Result JSON 返回,同时设置 HTTP 状态码。
 * 前端统一接收到 JSON,格式统一,方便处理错误提示
 * */
public class GlobalExceptionHandler {

  @ExceptionHandler(ResponseStatusException.class)
  public ResponseEntity<Result<?>> handleResponseStatusException(ResponseStatusException ex) {
//    从异常对象里获取 HTTP 状态码和提示信息:
    HttpStatus status = ex.getStatus();
    String reason = ex.getReason();
//    使用自定义统一返回类 Result 封装:
    Result<?> result = Result.error(status.value(), reason);

    // 返回 ResponseEntity,设置真正的 HTTP 状态码
    return new ResponseEntity<>(result, status);
  }

  /**
   * @ExceptionHandler(ResponseStatusException.class) 这个方法专门处理 ResponseStatusException 类型的异常。
   * Spring 中 ResponseStatusException 通常用于在 Controller 里主动抛出,指定 HTTP 状态码和原因:
   */

  @ExceptionHandler(Exception.class) // 获所有没有被其他 @ExceptionHandler 捕获的异常。
  public ResponseEntity<Result<?>> handleException(Exception ex) {
    Result<?> result = Result.error(500, "系统异常");
    return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

自定义Result.java 处理

java 复制代码
package com.sky.result;

import lombok.Data;

import java.io.Serializable;

/**
 * 统一返回结果类
 */
@Data
public class Result<T> implements Serializable {

  private static final long serialVersionUID = 1L;

  // 状态码
  private Integer code;

  // 消息
  private String message;

  // 数据
  private T data;

  // 时间戳
  private Long timestamp;

  // 请求路径(可选)
//  private String path;

  public Result() {
    this.timestamp = System.currentTimeMillis();
  }

  public Result(Integer code, String message, T data) {
    this.code = code;
    this.message = message;
    this.data = data;
    this.timestamp = System.currentTimeMillis();
  }

  // ========== 成功相关方法 ==========

  /**
   * 成功,无数据
   */
  public static <T> Result<T> success() {
    return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), null);
  }

  /**
   * 成功,有数据
   */
  public static <T> Result<T> success(T data) {
    return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
  }

  /**
   * 成功,自定义消息
   */
  public static <T> Result<T> success(String message) {
    return new Result<>(ResultCode.SUCCESS.getCode(), message, null);
  }

  /**
   * 成功,自定义消息和数据
   */
  public static <T> Result<T> success(String message, T data) {
    return new Result<>(ResultCode.SUCCESS.getCode(), message, data);
  }

  // ========== 失败相关方法 ==========

  /**
   * 失败,默认消息
   */
  public static <T> Result<T> error() {
    return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), ResultCode.INTERNAL_SERVER_ERROR.getMessage(), null);
  }

  /**
   * 失败,自定义消息
   */
  public static <T> Result<T> error(String message) {
    return new Result<>(ResultCode.INTERNAL_SERVER_ERROR.getCode(), message, null);
  }

  /**
   * 失败,使用枚举
   */
  public static <T> Result<T> error(ResultCode resultCode) {
    return new Result<>(resultCode.getCode(), resultCode.getMessage(), null);
  }

  /**
   * 失败,自定义状态码和消息
   */
  public static <T> Result<T> error(Integer code, String message) {
    return new Result<>(code, message, null);
  }

  // ========== 快捷业务方法 ==========

  /**
   * 参数验证失败
   */
  public static <T> Result<T> validateFailed() {
    return error(ResultCode.VALIDATE_FAILED);
  }

  public static <T> Result<T> validateFailed(String message) {
    return new Result<>(ResultCode.VALIDATE_FAILED.getCode(), message, null);
  }

  /**
   * 未授权
   */
  public static <T> Result<T> unauthorized() {
    return error(ResultCode.UNAUTHORIZED);
  }

  public static <T> Result<T> unauthorized(String message) {
    return new Result<>(ResultCode.UNAUTHORIZED.getCode(), message, null);
  }

  /**
   * 禁止访问
   */
  public static <T> Result<T> forbidden() {
    return error(ResultCode.FORBIDDEN);
  }

  /**
   * 数据不存在
   */
  public static <T> Result<T> notFound() {
    return error(ResultCode.DATA_NOT_FOUND);
  }

  public static <T> Result<T> notFound(String message) {
    return new Result<>(ResultCode.DATA_NOT_FOUND.getCode(), message, null);
  }

  /**
   * 数据已存在
   */
  public static <T> Result<T> dataExists() {
    return error(ResultCode.DATA_EXISTS);
  }

  /**
   * 登录失败
   */
  public static <T> Result<T> loginFailed() {
    return error(ResultCode.LOGIN_FAILED);
  }

  public static <T> Result<T> loginFailed(String message) {
    return new Result<>(ResultCode.LOGIN_FAILED.getCode(), message, null);
  }

  // ========== 工具方法 ==========

  /**
   * 通用构建方法
   */
  public static <T> Result<T> build(Integer code, String message, T data) {
    return new Result<>(code, message, data);
  }

  /**
   * Builder模式
   */
  public static <T> Builder<T> builder() {
    return new Builder<>();
  }

  /**
   * 判断是否成功
   */
  public boolean isSuccess() {
    return this.code != null && this.code.equals(ResultCode.SUCCESS.getCode());
  }

  public static class Builder<T> {
    private final Result<T> result;

    public Builder() {
      this.result = new Result<>();
    }

    public Builder<T> code(Integer code) {
      result.code = code;
      return this;
    }

    public Builder<T> message(String message) {
      result.message = message;
      return this;
    }

    public Builder<T> data(T data) {
      result.data = data;
      return this;
    }

    public Builder<T> path(String path) {
//      result.path = path;
      return this;
    }

    public Result<T> build() {
      return result;
    }
  }
}
相关推荐
f***28146 分钟前
Springboot中使用Elasticsearch(部署+使用+讲解 最完整)
spring boot·elasticsearch·jenkins
你怎么知道我是队长13 分钟前
C语言---文件读写
java·c语言·开发语言
咕白m62521 分钟前
通过 C# 快速生成二维码 (QR code)
后端·.net
踏浪无痕27 分钟前
架构师如何学习 AI:三个月掌握核心能力的务实路径
人工智能·后端·程序员
小毅&Nora1 小时前
【后端】【SpringBoot】① 源码解析:从启动到优雅关闭
spring boot·后端·优雅关闭
嘻哈baby1 小时前
从TIME_WAIT爆炸到端口耗尽:Linux短连接服务排查与优化
后端
wszy18091 小时前
外部链接跳转:从 App 打开浏览器的正确姿势
java·javascript·react native·react.js·harmonyos
开心就好20251 小时前
iOS应用性能监控全面解析:CPU、内存、FPS、卡顿与内存泄漏检测
后端
期待のcode1 小时前
认识Java虚拟机
java·开发语言·jvm
raining_peidx1 小时前
xxljob源码
java·开发语言