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;
}
}
}