泛型wrapper类实现接口统一响应,通过泛型t解耦数据与状态码,支持success/fail静态工厂方法、responsebodyadvice自动包装、注解或异常驱动动态装配,禁止嵌套包装与魔法数字。

用泛型集合 Wrapper 实现接口统一状态码的动态装配,核心在于把“数据”和“状态信息”解耦封装,再通过泛型让不同业务返回类型都能复用同一套响应结构。关键不是硬编码状态码,而是让 Wrapper 在构造时自动注入上下文中的状态(比如成功/失败)、消息、时间戳等,并支持链式构建或注解驱动的装配方式。
定义泛型 Wrapper 类,支持状态码与数据分离
Wrapper 应是一个不可变(或仅通过 Builder 构建)的容器类,泛型参数 T 表示业务数据类型。它至少包含:code(状态码)、msg(提示消息)、data(泛型数据)、timestamp(可选)。不建议直接暴露 setter,而是通过静态工厂方法或 Builder 模式装配:
- 成功响应:Wrapper.success(userList) → 自动设 code=200, msg="OK"
- 失败响应:Wrapper.fail(400, "用户名不能为空") → data 默认为 null
- 带数据的失败:Wrapper.fail(404, "用户不存在", null)
配合 Spring MVC 统一返回拦截(@ControllerAdvice + @ResponseBody)
在全局异常处理器或 ResponseBodyAdvice 中,对 Controller 返回值做自动包装。例如实现 ResponseBodyAdvice 接口,重写 beforeBodyWrite 方法:
- 若原返回值已是 Wrapper 类型,直接放行
- 若原返回值是普通对象(如 List
或 User),则自动套一层 Wrapper.success(...) - 可结合 @ResponseStatus 或自定义注解(如 @ApiResult)控制是否包装、指定默认 code/msg
支持运行时动态装配状态码(基于条件或注解)
状态码不应写死在 Wrapper 构造里,而应从执行上下文中提取。常见做法有:
- 在 Controller 方法上加 @ApiResponse(code = 201, msg = "创建成功"),ResponseBodyAdvice 解析该注解并注入 Wrapper
- 在 Service 层抛出自定义异常(如 BizException.withCode(422).message("参数校验失败")),全局异常处理器捕获后转为 Wrapper.fail(...)
- 使用 ThreadLocal 临时存状态上下文(慎用,注意清理),供 Wrapper 构造时读取
集合类型特殊处理:避免嵌套 Wrapper>>
当接口返回 List
- Wrapper.success(List
) → data 字段就是原始 List,不递归包装元素 - 如需分页,可扩展 Wrapper 为 PageWrapper
,含 total、list、page 等字段,仍保持单层包装 - 禁止在 MyBatis 的 ResultMap 或 DTO 中强行塞 Wrapper,那会破坏分层职责
不复杂但容易忽略的是:Wrapper 必须保持 JSON 序列化友好(无循环引用、getter 规范、空值处理一致),且所有状态码应集中管理(如定义 StatusCode.OK、StatusCode.NOT_FOUND 枚举),避免散落各处的魔法数字。











