本文目录导读:

在Java开发中,规范响应封装的核心目标是统一接口格式、降低前后端沟通成本、便于异常处理以及提升系统可维护性。
以下是业界常用的、规范的Java响应封装流程,通常基于Spring Boot和RESTful API。
核心规范原则
- 统一响应体(Response Entity):所有API接口返回统一的JSON结构。
- 状态码分离:使用HTTP Status Code(如200, 400, 500)表示通信层状态;使用业务状态码(如10000, 10001)表示业务逻辑状态。
- 泛型支持:支持泛型
T,让data字段指定不同类型。 - 异常统一处理:利用
@RestControllerAdvice全局捕获异常,自动包装为统一格式。
标准化响应类设计
通常定义一个泛型类 ApiResult<T> 作为所有接口的返回类型。
基础响应类
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiResult<T> implements Serializable {
// 业务状态码,非HTTP状态码
private Integer code;
// 提示信息
private String message;
// 数据负载
private T data;
// 私有构造器,禁止外部直接new
private ApiResult() { }
// 成功响应(无数据)
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> error(Integer code, String message) {
ApiResult<T> result = new ApiResult<>();
result.code = code;
result.message = message;
return result;
}
// 失败响应(使用枚举)
public static <T> ApiResult<T> error(ResultCode resultCode) {
ApiResult<T> result = new ApiResult<>();
result.code = resultCode.getCode();
result.message = resultCode.getMessage();
return result;
}
// 失败响应(默认错误)
public static <T> ApiResult<T> error() {
ApiResult<T> result = new ApiResult<>();
result.code = ResultCode.FAILED.getCode();
result.message = ResultCode.FAILED.getMessage();
return result;
}
// 链式调用方法
public ApiResult<T> message(String message) {
this.message = message;
return this;
}
}
业务状态码枚举
规范地定义业务状态码,避免魔法数字。
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ResultCode {
SUCCESS(200, "操作成功"),
FAILED(500, "操作失败"),
// 参数校验
PARAM_VALID_ERROR(1001, "参数校验失败"),
PARAM_MISSING(1002, "缺少必要参数"),
// 鉴权相关
UNAUTHORIZED(4010, "未登录或Token已过期"),
FORBIDDEN(4030, "无权限访问"),
// 业务异常
USER_NOT_FOUND(2001, "用户不存在"),
PRODUCT_STOCK_SHORT(3001, "库存不足"),
// 系统异常
SYSTEM_ERROR(5000, "系统繁忙,请稍后重试"),
REMOTE_CALL_ERROR(5001, "远程调用失败");
private final Integer code;
private final String message;
}
统一异常处理流程
规范不仅体现在成功时,更重要的是异常情况下的统一响应。
自定义业务异常类
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final Integer code;
private final String message;
public BusinessException(ResultCode resultCode) {
super(resultCode.getMessage());
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
}
全局异常处理器
使用@RestControllerAdvice拦截所有异常,统一包装为 ApiResult。
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public ApiResult<?> handleBusinessException(BusinessException e) {
log.warn("业务异常: code={}, message={}", e.getCode(), e.getMessage());
return ApiResult.error(e.getCode(), e.getMessage());
}
// 处理参数校验异常(@Validated)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResult<?> handleValidationException(MethodArgumentNotValidException e) {
FieldError fieldError = e.getBindingResult().getFieldError();
String errorMsg = fieldError != null ? fieldError.getDefaultMessage() : "参数校验失败";
// 这里也可以返回ResultCode.PARAM_VALID_ERROR
return ApiResult.error(ResultCode.PARAM_VALID_ERROR.getCode(), errorMsg);
}
// 处理未知异常(兜底)
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult<?> handleException(Exception e) {
log.error("系统异常: ", e);
// 生产环境建议不要直接返回堆栈信息
return ApiResult.error(ResultCode.SYSTEM_ERROR);
}
}
在Controller中的使用规范
规范的最佳实践:Controller层只关心业务逻辑,返回 ApiResult<T>,异常由全局处理器接管。
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/login")
public ApiResult<String> login(@Valid @RequestBody LoginRequest loginReq) {
// 假设login返回Token
String token = userService.login(loginReq);
// 成功返回,data为token
return ApiResult.success(token);
}
@GetMapping("/{id}")
public ApiResult<UserVO> getUserInfo(@PathVariable Long id) {
// 如果用户不存在,service层直接抛出 BusinessException(USER_NOT_FOUND)
UserVO userVO = userService.getUserInfo(id);
return ApiResult.success(userVO);
}
@PostMapping
public ApiResult<Void> createUser(@Valid @RequestBody UserCreateRequest req) {
userService.createUser(req);
// 不需要数据时,返回成功响应
return ApiResult.success();
}
}
进阶规范技巧
-
分页统一封装:建议对分页数据额外封装
PageResult<T>,包含total,pages,records等字段。@Data public class PageResult<T> { private long total; private long page; private long size; private List<T> records; }使用时:
ApiResult.success(new PageResult<>(page.getTotal(), ...)) -
日志链路追踪:在异常响应中,可以返回一个唯一的
traceId(从MDC获取),方便排错。public class ApiResult<T> { // ... private String traceId; // 添加追踪ID } -
国际化支持:message字段不直接写死中文,而是从i18n资源文件中获取,根据请求头
Accept-Language动态选择语言。 -
使用
ResponseEntity控制HTTP状态码:当需要精细控制HTTP状态码时(如201 Created),可以这样做:@PostMapping public ResponseEntity<ApiResult<Void>> createUser(@Valid @RequestBody Req req) { userService.createUser(req); return ResponseEntity.status(HttpStatus.CREATED).body(ApiResult.success()); }
规范带来的好处
| 场景 | 不规范的响应 | 规范后的响应 |
|---|---|---|
| 查询成功 | { "id": 1, "name": "张三" } |
{ "code": 200, "message": "操作成功", "data": { "id": 1, "name": "张三" } } |
| 参数错误 | 400 + 一段HTML错误信息 |
{ "code": 1001, "message": "用户名不能为空", "data": null } |
| 未登录 | 302 重定向 |
{ "code": 4010, "message": "未登录或Token已过期", "data": null } |
| 服务器崩溃 | 500 + 堆栈信息 |
{ "code": 5000, "message": "系统繁忙,请稍后重试", "data": null } |
规范的Java响应封装流程 = 统一响应类 + 业务状态码枚举 + 全局异常处理器。
这样做之后,前端只需统一解析 code 和 message,无需为不同接口编写不同逻辑;后端只需正常编写业务代码,异常自然会被捕获并包装,这套规范在大多数Java项目中(Spring Boot + RESTful API)都是通用的最佳实践。