Java统一返回案例如何封装

wen java案例 24

本文目录导读:

Java统一返回案例如何封装

  1. 核心实体类封装
  2. 使用示例
  3. 前端收到的 JSON 示例
  4. 最佳实践建议

在Java后端开发中,统一返回格式的核心目的是让前端能够以统一的结构解析后端响应,便于处理成功、失败、异常等不同情况,下面我会介绍一个经典的封装案例,涵盖泛型、静态工厂方法、枚举状态码等最佳实践。

核心实体类封装

定义状态码枚举(强烈推荐)

public enum ResultCode {
    SUCCESS(200, "操作成功"),
    FAILED(500, "操作失败"),
    VALIDATE_FAILED(400, "参数校验失败"),
    UNAUTHORIZED(401, "未登录或token已过期"),
    FORBIDDEN(403, "没有相关权限"),
    NOT_FOUND(404, "资源不存在"),
    SERVER_ERROR(500, "服务器内部错误");
    private final int code;
    private final String message;
    ResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public int getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
}

统一返回类 ApiResult<T>

import lombok.Data;
import java.io.Serializable;
@Data
public class ApiResult<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private int code;
    private String message;
    private T data;
    private long timestamp; // 可选,建议加上方便排查
    // 私有构造器,防止外部直接实例化
    private ApiResult() {
        this.timestamp = System.currentTimeMillis();
    }
    // ========== 成功响应(无数据返回) ==========
    public static <T> ApiResult<T> success() {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.SUCCESS.getCode();
        result.message = ResultCode.SUCCESS.getMessage();
        return result;
    }
    // ========== 成功响应(有数据) ==========
    public static <T> ApiResult<T> success(T data) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.SUCCESS.getCode();
        result.message = ResultCode.SUCCESS.getMessage();
        result.data = data;
        return result;
    }
    // ========== 成功响应(自定义消息) ==========
    public static <T> ApiResult<T> success(String message, T data) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.SUCCESS.getCode();
        result.message = message;
        result.data = data;
        return result;
    }
    // ========== 失败响应(默认500) ==========
    public static <T> ApiResult<T> failed() {
        return failed(ResultCode.FAILED);
    }
    public static <T> ApiResult<T> failed(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.FAILED.getCode();
        result.message = message;
        return result;
    }
    // ========== 自定义状态码失败响应 ==========
    public static <T> ApiResult<T> failed(ResultCode resultCode) {
        ApiResult<T> result = new ApiResult<>();
        result.code = resultCode.getCode();
        result.message = resultCode.getMessage();
        return result;
    }
    public static <T> ApiResult<T> failed(ResultCode resultCode, String message) {
        ApiResult<T> result = new ApiResult<>();
        result.code = resultCode.getCode();
        result.message = message;
        return result;
    }
    // ========== 便捷方法:参数校验失败 ==========
    public static <T> ApiResult<T> validateFailed(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.VALIDATE_FAILED.getCode();
        result.message = message;
        return result;
    }
    // ========== 便捷方法:未授权 ==========
    public static <T> ApiResult<T> unauthorized(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.UNAUTHORIZED.getCode();
        result.message = message;
        return result;
    }
    // ========== 便捷方法:无权限 ==========
    public static <T> ApiResult<T> forbidden(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.code = ResultCode.FORBIDDEN.getCode();
        result.message = message;
        return result;
    }
    // ========== 链式调用支持(可选) ==========
    public ApiResult<T> code(int code) {
        this.code = code;
        return this;
    }
    public ApiResult<T> message(String message) {
        this.message = message;
        return this;
    }
    public ApiResult<T> data(T data) {
        this.data = data;
        return this;
    }
}

使用示例

Controller 中直接使用

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    public ApiResult<User> getUser(@PathVariable Long id) {
        // 模拟查询
        User user = userService.getById(id);
        if (user == null) {
            return ApiResult.failed(ResultCode.NOT_FOUND, "用户不存在");
        }
        return ApiResult.success(user);
    }
    @PostMapping
    public ApiResult<Void> createUser(@Valid @RequestBody UserCreateDTO dto) {
        // 参数校验失败会由全局异常处理捕获,这里假设业务正常
        userService.create(dto);
        return ApiResult.success("创建成功", null);
    }
}

配合全局异常处理(Spring Boot)

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining("; "));
        return ApiResult.validateFailed(message);
    }
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ApiResult<Void> handleBusinessException(BusinessException e) {
        return ApiResult.failed(e.getCode(), e.getMessage());
    }
    // 处理其他未捕获异常
    @ExceptionHandler(Exception.class)
    public ApiResult<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return ApiResult.failed(ResultCode.SERVER_ERROR, "系统繁忙,请稍后再试");
    }
}

自定义业务异常类

public class BusinessException extends RuntimeException {
    private int code;
    private String message;
    public BusinessException(ResultCode resultCode) {
        super(resultCode.getMessage());
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
    }
    public BusinessException(ResultCode resultCode, String message) {
        super(message);
        this.code = resultCode.getCode();
        this.message = message;
    }
    // getter/setter
}

前端收到的 JSON 示例

// 成功响应(有数据)
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "username": "admin",
    "email": "admin@example.com"
  },
  "timestamp": 1691234567890
}
// 成功响应(无数据)
{
  "code": 200,
  "message": "操作成功",
  "data": null,
  "timestamp": 1691234567890
}
// 失败响应
{
  "code": 400,
  "message": "用户名不能为空",
  "data": null,
  "timestamp": 1691234567890
}
// 未授权
{
  "code": 401,
  "message": "未登录或token已过期",
  "data": null,
  "timestamp": 1691234567890
}
// 服务器内部错误
{
  "code": 500,
  "message": "系统繁忙,请稍后再试",
  "data": null,
  "timestamp": 1691234567890
}

最佳实践建议

不要直接在返回对象上使用 @Data

  • 如果使用 Lombok @Data,记得加上 @Accessors(chain = true) 以支持链式调用。

统一时间戳格式

  • 建议在 ApiResult 的构造器中设置 timestamp,或者使用 Instant.now().toEpochMilli()

避免返回敏感信息

  • data 字段中,使用 DTO(数据传输对象)而非实体类,避免暴露密码等敏感字段。

分页查询统一包装

@GetMapping("/page")
public ApiResult<PageResult<User>> getUserPage(@RequestParam int page, @RequestParam int size) {
    PageResult<User> pageResult = userService.getPage(page, size);
    return ApiResult.success(pageResult);
}
// PageResult 示例
@Data
public class PageResult<T> {
    private List<T> list;
    private long total;
    private int page;
    private int size;
}

与 Spring 的 ResponseEntity 结合

如果你需要控制 HTTP 状态码(201 Created),可以这样:

@PostMapping
public ResponseEntity<ApiResult<User>> createUser(@RequestBody User user) {
    User createdUser = userService.create(user);
    return ResponseEntity.status(HttpStatus.CREATED)
            .body(ApiResult.success("创建成功", createdUser));
}
特性 说明
类型安全 使用泛型 T 保证 data 字段的编译时类型检查
易用性 静态工厂方法(success()failed())让返回代码简洁
可扩展 枚举 ResultCode 统一管理状态码,新增状态码只需添加枚举项
异常处理 全局异常拦截器 @RestControllerAdvice 自动捕获异常并转换

这种封装方案在实际项目中经过大量验证,适用于微服务、单体应用,并且可以无缝集成到 Spring Boot 生态中。

抱歉,评论功能暂时关闭!