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;
    }
  }
}
相关推荐
苏三的开发日记19 分钟前
Java后台定时器导致系统奔溃的原因分析
后端
remaindertime20 分钟前
基于Ollama和Spring AI:实现本地大模型对话与 RAG 功能
人工智能·后端·ai编程
Lear21 分钟前
Spring Boot异步任务实战:优化耗时操作,提升系统性能
后端
编程火箭车22 分钟前
【Java SE 基础学习打卡】14 Java 注释
java·编程规范·代码注释·api文档·代码可读性·javadoc·文档注释
雁于飞30 分钟前
分布式基础
java·spring boot·分布式·spring·wpf·cloud native
q***2511 小时前
java进阶1——JVM
java·开发语言·jvm
望眼欲穿的程序猿1 小时前
Win系统Vscode+CoNan+Cmake实现调试与构建
c语言·c++·后端
while(1){yan}1 小时前
线程的状态
java·开发语言·jvm
豐儀麟阁贵1 小时前
8.3 Java常见的异常类
java·开发语言