本文目录导读:

在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 生态中。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播