Spring Boot 统一响应体封装
统一响应体封装使API返回格式一致,便于前端统一处理和错误管理。
响应体设计
基本结构
Java
@Data
public class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> success() {
return success(null);
}
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
public static <T> Result<T> fail(int code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> fail(ErrorCode errorCode) {
return fail(errorCode.getCode(), errorCode.getMessage());
}
}
使用示例
Java
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public Result<User> getById(@PathVariable Long id) {
return Result.success(userService.getById(id));
}
@PostMapping
public Result<User> create(@RequestBody UserDTO dto) {
return Result.success(userService.create(dto));
}
}
ResponseBodyAdvice自动包装
实现
Java
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
// 排除已经是Result类型的返回值
return !returnType.getParameterType().equals(Result.class);
}
@Override
public Object beforeBodyWrite(Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
return Result.success(body);
}
}
String类型返回值需特殊处理,否则会抛出ClassCastException。
String类型处理
Java
@Override
public Object beforeBodyWrite(Object body, ...) {
if (body instanceof String) {
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(Result.success(body));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
return Result.success(body);
}
分页响应封装
Java
@Data
public class PageResult<T> {
private List<T> list;
private long total;
private int pageNum;
private int pageSize;
private int pages;
public static <T> PageResult<T> of(List<T> list, long total, int pageNum, int pageSize) {
PageResult<T> result = new PageResult<>();
result.setList(list);
result.setTotal(total);
result.setPageNum(pageNum);
result.setPageSize(pageSize);
result.setPages((int) Math.ceil((double) total / pageSize));
return result;
}
}
// 使用
@GetMapping("/page")
public Result<PageResult<User>> page(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize) {
Page<User> page = userService.page(pageNum, pageSize);
return Result.success(PageResult.of(page.getContent(), page.getTotal(), pageNum, pageSize));
}
排除特定接口
Java
// 自定义注解标记不包装的接口
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreResponseWrap {}
// ResponseBodyAdvice中排除
@Override
public boolean supports(MethodParameter returnType,
Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getParameterType().equals(Result.class)
&& !returnType.hasMethodAnnotation(IgnoreResponseWrap.class)
&& !Objects.requireNonNull(returnType.getMethod()).getDeclaringClass()
.isAnnotationPresent(IgnoreResponseWrap.class);
}
要点总结
- 使用泛型Result封装统一响应
- 静态工厂方法简化对象创建
- ResponseBodyAdvice实现自动包装
- 注意String类型特殊处理
- 分页响应使用PageResult封装
📝 发现内容有误?点击此处直接编辑