Skip to content

整体架构

模块组成

整个模块 5 个 Java 文件,~600 行:

职责
SwaggerConfig注册 OpenAPI Bean(title / version / contact / servers)与 OperationCustomizer Bean
GlobalResultOperationCustomizer拦截每个 Operation 的响应 schema,包一层 Result 结构;遇到 @RawResponse 跳过
SchemaBuilder工具类,构建 Result schema、$ref 引用、数组 schema
ExampleDataGenerator工具类,生成示例数据(UserDTO 示例、Result 完整示例)
SwaggerConstants字段名、默认值、媒体类型常量、已知实体类型清单

装配链路

本模块同样没有 AutoConfiguration.importsSwaggerConfig 的 @Configuration 通过组件扫描注册,因此装配前提与 core 模块一致:业务工程的启动类必须能扫到 cn.cvking.forge

关键依赖

GroupIdArtifactId版本用途
org.springdocspringdoc-openapi-starter-webmvc-ui2.8.9OpenAPI 3 自动扫描与 Swagger UI
com.github.xiaoyminknife4j-openapi3-jakarta-spring-boot-starter4.4.0Knife4j 中文增强 UI
cn.cvkingforge-api(parent)Result 字段名约定
cn.cvkingforge-processor(parent)@RawResponse 注解
org.springframework.bootspring-boot-starter-web(parent)Spring MVC,依赖传递保证 Springdoc 可工作

注意:本模块依赖 forge-core。所以如果业务方只想要 Swagger 文档而不要 core 的运行时包装也可以独立引入 swagger 模块,文档层会照常包出 Result schema,只是运行时的实际返回不会被框架自动包装。

与 core / processor 的关系

  • 与 processor 的关系:swagger 直接消费 @RawResponse 注解,决定文档层是否跳过包装。注解契约是由 processor 模块约定的,swagger 只读不改
  • 与 core 的关系:没有直接依赖。两个模块在「Result 字段结构」上保持一致是靠 SwaggerConstantsResult.java 的字段约定,而非通过共享代码

这是有意为之的解耦

让 swagger 不依赖 core 的好处:哪怕业务方未来想换掉 core 模块(例如换成自研的统一响应实现),只要 Result 的字段名(success / code / message / data)不变,swagger 模块继续可用。

设计取舍

选项选择理由
装配方式@Configuration 自动扫描与 core 一致,零样板
与 core 的耦合解耦,只共享字段约定提高可换性
配置项形态OpenAPI Bean 硬编码 + springdoc / knife4j 标准配置短期内够用;演进方向是抽 @ConfigurationProperties
包装机制OperationCustomizer 而不是修改 Springdoc 内部走 Springdoc 官方扩展点,版本升级不易破坏
Customizer OrderOrdered.LOWEST_PRECEDENCE让其它 customizer 先把 schema 处理完,最后统一包装一次
示例数据内置 UserDTO 示例让框架自身演示场景有完整文档;业务方需要其它类型时按 Schema 构建 · 扩展点 处理

已知待改进点

  • OpenAPI Bean 字段全部硬编码,未抽配置类
  • 内置示例数据只覆盖 UserDTO,业务实体需要文档层示例时无法自动生成
  • 路径白名单(@RawResponse 判断之外)没有暴露给业务方
  • 当响应是已经是 Result 形状时(属性集合命中 success/code/message/data),customizer 会用空 ObjectSchema 包出新的 Result,可能不是业务方期望的行为

详细原理见 响应包装定制器Schema 构建