# Swagger 响应状态自动列出 6 位业务码(#1412)

**日期**: 2026-04-25
**关联 PR**: #1413(初版)/ #1414 / #1415 / #1416(hotfix 链)
**工单**: [#1412](https://git.1814.love:8443/wx/HL/issues/1412)

---

## 改造前
Knife4j 接口文档每个接口的「响应状态」区只有:
- 200 OK
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found

#1391 引入的 6 位业务码(如 `400301 产品下架` / `500311 订单状态不允许取消`)前端在文档里看不到。

## 改造后
每个接口的「响应状态」区显示 **193 个状态码**:
- HTTP 标准 4 个(200/401/403/404 保留)
- **6 位业务码 189 个**(从 ErrorCodeRegistry 自动收集,含 message)

### 实例(GET /admin/agreement/page)
```
状态码    说明
200       OK
401       Unauthorized
403       Forbidden
404       Not Found
100000    系统异常,请稍后重试
100001    参数非法: {0}
100002    数据不存在
100003    操作不允许: {0}
100501    {0}                          ← 流控
100502    {0}                          ← 幂等拦截
100901    远程服务返回数据为空           ← Feign 透传
... (189 个 6 位业务码)
```

## 实现路径(踩坑总结)
1. **PR #1413**:`Docket.globalResponseMessage` 注入 — Docket bean 创建时 `ErrorCodeRegistry.scan()` 还没跑(在 ApplicationRunner 阶段),codeMap 空,失败
2. **PR #1414**:改用 `OperationBuilderPlugin` — 仍空,因为 plugin 也在 ApplicationRunner 之前被 swagger 触发
3. **PR #1415**:删除 5 个 Knife4jConfig 的 `globalResponseMessage` 残留(避免覆盖 plugin)
4. **PR #1416**:**根本解** — `ErrorCodeRegistry` 改用 `@PostConstruct` 在 Bean 实例化时立即扫描,所有下游 Bean 拿到非空 codeMap

## 影响
- 5 个 MVC 业务服务(user/resource/product-v2/order-v2/mp)swagger 全生效
- 接口数据结构无变化,只是**文档**新增响应状态展示
- 业务接口/前端调用无需改动

## 经验沉淀
**Spring Boot Bean 启动顺序**:`ApplicationRunner.run()` 在 `ApplicationContext.refresh()` 完全完成之后运行,但 swagger 等组件可能在 refresh 过程中已构建 OpenAPI 模型,此时 ApplicationRunner 还没跑。需要在 Bean 创建期就完成扫描的逻辑应该用 `@PostConstruct`。

## 验证
浏览器访问任一接口的"响应状态"区,应看到 193 行响应码。
