Spring Boot 使用 SpringDoc 构建 OpenAPI 3 接口文档
在 Spring Boot 项目中,接口文档不应该是一份需要人工同步维护的附属 Word 文档,而应该尽可能从真实的 Controller、DTO、参数约束和接口注解中生成。SpringDoc 正是 Spring Boot 生态中常用的 OpenAPI 文档生成方案。本文围绕 SpringDoc 的工作原理、Spring Boot 3/4 版本选择、Swagger UI、OpenAPI 注解、接口分组、JWT 鉴权、WebFlux、生产环境控制以及 Springfox 迁移等内容,整理一套适合实际项目使用的 API 文档方案。
为什么需要 SpringDoc
REST API 开发中有一个长期存在的问题:代码和接口文档很容易失去同步。
如果接口文档完全依靠开发人员手工维护,随着项目持续迭代,很容易出现下面这些情况:
- Controller 已经增加了参数,文档没有更新;
- DTO 字段已经修改,文档仍然描述旧结构;
- HTTP 状态码和错误响应发生变化,调用方却不知道;
- 一个接口究竟需要 Header、Query Parameter 还是 Request Body,只能翻代码;
- 前端、测试、第三方系统都在使用不同版本的接口说明。
Swagger、OpenAPI 和 SpringDoc 解决的核心问题,就是把 API 的机器可读定义和实际应用代码建立联系。
SpringDoc 会在 Spring Boot 应用运行时分析 Spring 配置、Controller、Java 类型以及相关注解,将这些信息转换成 OpenAPI 描述,并输出 JSON/YAML,再由 Swagger UI 等工具进行可视化。SpringDoc 官方明确说明,它通过运行时分析应用配置、类结构和注解推断 API 语义。
整个过程可以抽象为:
flowchart LR
A["Spring MVC / WebFlux<br/>Controller"]
B["DTO / VO / Record"]
C["Bean Validation<br/>@NotNull / @Size ..."]
D["Swagger Annotations<br/>@Operation / @Schema ..."]
E["SpringDoc"]
F["OpenAPI Model"]
G["/v3/api-docs<br/>JSON"]
H["/v3/api-docs.yaml<br/>YAML"]
I["Swagger UI"]
J["Scalar"]
K["代码生成 / 测试 / API Gateway / CI"]
A --> E
B --> E
C --> E
D --> E
E --> F
F --> G
F --> H
G --> I
G --> J
G --> K
H --> K
SpringDoc 本身需要和另外几个容易混淆的概念区分开。
| 名称 | 作用 |
|---|---|
| OpenAPI Specification | 描述 HTTP API 的标准规范 |
| Swagger Annotations | Java 中描述 OpenAPI 信息的一组注解 |
| Swagger UI | 将 OpenAPI 文档渲染成交互式网页 |
| SpringDoc | 从 Spring Boot 应用中自动生成 OpenAPI 描述 |
| Scalar | 另一种 OpenAPI 可视化和交互式 API 客户端 |
所以准确地说,并不是“SpringDoc 生成 Swagger”,而是:
SpringDoc 根据 Spring 应用生成 OpenAPI 文档,Swagger UI 再消费这份 OpenAPI 文档进行展示。
SpringDoc 也并不是 Spring Framework 官方模块,而是一个社区维护项目。
SpringDoc 与 Springfox 的关系
在较早的 Spring Boot 项目中,经常能看到:
1 | |
以及:
1 | |
这一套属于 Springfox 体系。
在 Spring Boot 3、Spring Framework 6 和 Jakarta EE 命名空间成为主流之后,更常见的方案是:
1 | |
SpringDoc 官方迁移指南也明确要求从 Springfox 迁移时删除 Springfox/Swagger 2 相关依赖,改为 SpringDoc starter,并把 Swagger 2 注解迁移到 io.swagger.v3.oas.annotations 下的 OpenAPI 3 注解。
常见注解对应关系如下:
| Springfox / Swagger 2 | OpenAPI 3 |
|---|---|
@Api |
@Tag |
@ApiOperation |
@Operation |
@ApiImplicitParam |
@Parameter |
@ApiImplicitParams |
@Parameters |
@ApiModel |
@Schema |
@ApiModelProperty |
@Schema |
@ApiParam |
@Parameter |
@ApiResponse(code = ...) |
@ApiResponse(responseCode = ...) |
@ApiIgnore |
@Hidden、@Operation(hidden = true) 等 |
SpringDoc 官方还指出,如果原来有多个 Springfox Docket,可以使用 GroupedOpenApi 进行替换。
Spring Boot 与 SpringDoc 的版本关系
SpringDoc 是一个与 Spring Boot 底层 Web API 联系比较紧密的组件,因此版本不能随便选。
Spring Boot 3 与 Spring Boot 4 分别对应不同的 SpringDoc 主版本:
1 | |
SpringDoc v2 官方兼容矩阵给出的历史关系为:
| Spring Boot | SpringDoc |
|---|---|
| 3.0.x | 2.0.x ~ 2.1.x |
| 3.1.x | 2.2.x |
| 3.2.x | 2.3.x ~ 2.5.x |
| 3.3.x | 2.6.x |
| 3.4.x | 2.7.x ~ 2.8.x |
| 3.5.x | 2.8.x |
| 4.x | 3.x |
需要注意一个现实中的版本细节。
截至 2026 年 8 月,SpringDoc 已经同时维护 Spring Boot 3 和 Spring Boot 4 两条主要版本线:
springdoc-openapi 2.9.0springdoc-openapi 3.1.0
其中 2.9.0 的发布说明已经升级到 Spring Boot 3.5.16,而 3.1.0 对应 Spring Boot 4.x。
因此项目选型时不要机械照抄旧博客中的版本号,例如早期教程中的:
1 | |
或者:
1 | |
这些版本在其发布时间是合理的,但并不意味着今天创建 Spring Boot 3.5 项目时还应该继续使用它们。
更稳妥的规则是:
先确定 Spring Boot 版本,再选择与之匹配的 SpringDoc 主版本和维护版本。
本文后面的 Spring Boot 3 示例以当前 SpringDoc 2.x starter 体系为基础。
Spring Boot 3 快速接入 SpringDoc
Spring MVC 项目
如果项目使用:
1 | |
并且希望同时生成 OpenAPI 文档和 Swagger UI,可以增加:
1 | |
SpringDoc 的 starter 已经包含 Swagger UI 所需的依赖,因此不需要再额外添加 Swagger UI。SpringDoc v2 文档给出的默认 OpenAPI JSON 地址是 /v3/api-docs,同时还可以通过 /v3/api-docs.yaml 获取 YAML 格式描述。
启动应用后可以访问:
1 | |
获取 OpenAPI JSON:
1 | |
YAML:
1 | |
Swagger UI:
1 | |
不同版本和重定向方式下,也经常能看到实际 UI 静态资源入口:
1 | |
早期 Spring Boot 3 教程也经常使用 /swagger-ui/index.html 直接访问页面。
只生成 OpenAPI,不提供 Swagger UI
有些服务本身并不需要提供网页文档,只希望:
- API Gateway 获取 OpenAPI;
- CI 导出 API Schema;
- OpenAPI Generator 生成 SDK;
- API 管理平台统一展示。
这种情况下可以只使用:
1 | |
这个 starter 提供 OpenAPI endpoint,而不包含 Swagger UI。
在微服务生产环境中,这种方式往往比每个服务都部署 Swagger UI 更轻量。
WebFlux 项目如何接入
如果项目使用的是:
1 | |
则不要使用 webmvc starter。
提供 Swagger UI:
1 | |
只需要 OpenAPI:
1 | |
SpringDoc 对 Spring MVC 和 WebFlux 都提供对应 starter。
这点非常重要:
1 | |
项目本身是什么 Web 技术栈,就选择对应模块,不要为了 Swagger UI 随意混入另一个 Web Stack。
最基本的 application.yml 配置
很多项目其实不需要大量配置。
一个比较常见的开发环境配置可以写成:
1 | |
SpringDoc 默认:
1 | |
并允许通过 packages-to-scan、paths-to-match、paths-to-exclude 等属性控制哪些接口进入 OpenAPI 文档。
例如只扫描业务 API:
1 | |
排除内部接口:
1 | |
对于大型项目,这比“所有 Controller 一股脑全部展示”更容易维护。
SpringDoc 到底扫描了什么
SpringDoc 并不是简单扫描几个 Swagger 注解。
它会综合分析:
1 | |
因此 SpringDoc 的最佳使用方式不是:
每个 Java 字段都重新人工描述一遍 Java 类型。
而应该让 SpringDoc 自动推断能够推断的部分,只给它补充业务语义。
例如:
1 | |
即使完全没有 Swagger 注解,SpringDoc 也能够识别:
- HTTP Method:GET;
- Path:
/{id}; id是 Path Parameter;- 返回对象类型是
BookDTO。
注解真正应该补充的是:
1 | |
最常用的 OpenAPI 注解
@Tag:描述 Controller 或 API 分组
1 | |
Swagger UI 通常会按照 Tag 对接口进行分组。
@Operation:描述具体操作
1 | |
其中:
1 | |
适合一句话说明操作用途。
1 | |
适合补充更加详细的行为说明。
不要写成:
1 | |
这种注解虽然存在,却没有增加任何信息。
@Parameter:描述请求参数
1 | |
查询参数同样可以描述:
1 | |
如果某个参数不应该出现在接口文档中,可以使用:
1 | |
SpringDoc 也会自动忽略部分 Spring MVC 注入参数,例如 Principal、Locale、HttpServletRequest 和 HttpServletResponse 等。
@Schema:描述 DTO
例如:
1 | |
@Schema 可以用于:
- 类;
- 字段;
- 枚举;
- 方法参数;
- 请求体模型;
- 响应模型。
早期 Swagger 2 中:
1 | |
基本都迁移为 OpenAPI 3 的:
1 | |
Bean Validation 与 Schema
可以把 Bean Validation 和 OpenAPI 描述组合起来:
1 | |
SpringDoc 支持根据 JSR-303/Bean Validation 的相关约束生成 Schema 信息,例如 @NotNull、@Min、@Max、@Size 等。
这样:
1 | |
仍然负责真正的运行时校验;
而:
1 | |
负责补充接口语义。
两者职责不要反过来。
描述响应状态码
一个接口不应该只有:
1 | |
例如查询资源时,很可能同时存在:
1 | |
可以通过 @ApiResponses 描述:
1 | |
如果需要进一步指定 Response Body:
1 | |
SpringDoc 还能够和 @ControllerAdvice、@ResponseStatus 配合生成通用错误响应。
工程上建议统一设计错误模型,例如:
1 | |
然后让业务异常、参数异常、权限异常都遵循统一响应结构。
这样生成出来的 OpenAPI 才真正具有消费价值。
一个相对完整的 Controller 示例
把前面的内容组合起来:
1 | |
这里有一个很重要的设计思想:
Spring MVC 注解描述 HTTP 行为,Bean Validation 描述约束,OpenAPI 注解补充接口语义。
不要试图让 Swagger 注解代替真正的接口设计。
配置 API 基本信息
如果什么都不配置,SpringDoc 仍然能够生成文档。
但实际项目通常需要设置:
- API 名称;
- API 版本;
- 描述;
- 联系信息;
- License;
- Server;
- Security Scheme。
可以创建一个 OpenAPI Bean:
1 | |
SpringDoc 官方支持通过 OpenAPI Bean 定制整个 OpenAPI Model,并建议将 @OpenAPIDefinition、@SecurityScheme 等定义放在 Spring 管理的 Bean 中。
也可以使用注解:
1 | |
两种方式没有必要同时大量使用。
如果需要动态组合配置、统一添加 Security Scheme、Server 或 Components,使用 OpenAPI Bean 通常更加灵活。
Pageable 参数为什么需要 @ParameterObject
例如 Spring Data 中经常有这样的接口:
1 | |
为了让分页参数清晰地展开为:
1 | |
可以使用:
1 | |
SpringDoc 从 v1.6.0 开始已经内置了 Pageable 支持。
对于普通查询 DTO 同样可以:
1 | |
例如:
1 | |
SpringDoc 官方 FAQ 特别说明,@ParameterObject 会把对象字段展开为独立请求参数,但它不支持嵌套 Parameter Object,并且依赖标准 getter 读取属性。
所以对于:
1 | |
@ParameterObject 很适合;
但对于复杂嵌套结构,还是应该重新设计查询模型或者使用 Request Body。
使用 GroupedOpenApi 拆分大型接口文档
当系统接口越来越多时,把数百个接口全部放在一个 Swagger UI 中会越来越难找。
例如:
1 | |
可以通过 GroupedOpenApi 分组。
1 | |
生成后通常可以访问:
1 | |
SpringDoc 官方规定,每一个 group 都需要唯一的 groupName,并可以按照 Path 和 Package 进行筛选。
除了路径,还可以:
1 | |
或者组合:
1 | |
如果不希望写 Java Bean,还可以通过配置创建 group:
1 | |
SpringDoc 支持直接使用 springdoc.group-configs 定义组,此时不需要额外声明 GroupedOpenApi Bean。
对于模块化单体或者微服务,推荐优先按照业务域而不是 Controller 类名进行分组。
例如:
1 | |
这样的文档结构比:
1 | |
更能反映真实业务边界。
Spring Security + JWT 接入 Swagger UI
真实系统通常都会有认证。
例如:
1 | |
这里不要给每一个接口都手工增加:
1 | |
OpenAPI 对 Authorization 有专门的 Security Scheme 模型。SpringDoc 官方也明确建议通过 SecurityRequirement 和 SecurityScheme 描述 Bearer Token。
可以配置:
1 | |
然后在需要认证的接口上:
1 | |
也可以通过:
1 | |
把认证要求设置成全局规则。
但如果系统同时存在:
1 | |
这类匿名接口,就不要简单把所有 API 全局标记为必须 JWT。
Spring Security 需要放行 Swagger 路径
即使 SpringDoc 成功生成了文档,如果 Spring Security 把文档接口全部拦截,浏览器仍然无法正常打开 Swagger UI。
Spring Security 6 常见配置为:
1 | |
开发和测试环境这样做通常比较方便。
但生产环境是否应该开放 Swagger,需要重新评估,而不是机械 permitAll()。
Swagger UI 常用配置
Swagger UI 自己拥有大量配置项,SpringDoc 可以通过:
1 | |
直接映射这些配置。
例如:
1 | |
operations-sorter
1 | |
可以按照 HTTP Method 排序。
也可以:
1 | |
按照路径字母排序。
tags-sorter
1 | |
让 Tag 按字母排序。
大型系统如果不指定排序方式,随着接口增长,Swagger UI 很容易显得杂乱。
doc-expansion
1 | |
默认折叠所有接口。
接口几十个甚至几百个以后,这个配置非常实用。
filter
1 | |
Swagger UI 页面会提供过滤输入框,可按 Tag 等信息查找接口。
persist-authorization
1 | |
允许 Swagger UI 保存认证信息,刷新页面后不需要再次输入 Token。默认值为 false。
开发环境比较方便,但在公共电脑或共享浏览器中需要谨慎启用。
OpenAPI 3.0 与 3.1
现代 SpringDoc 版本已经支持 OpenAPI 3.1。
在 SpringDoc 2.9.0 的配置中:
1 | |
默认值是:
1 | |
因此打开:
1 | |
可能看到:
1 | |
这点对后续工具链很重要。
例如:
1 | |
如果后续某个工具仍然只完整支持 OpenAPI 3.0,就要检查整个链路,而不能只确认 Swagger UI 页面“看起来正常”。
API 文档已经不只是页面,它本质上是一个机器可消费的契约文件。
Swagger UI 之外:Scalar
现在 SpringDoc 还支持 Scalar。
SpringDoc v2 提供:
1 | |
WebFlux 则是:
1 | |
默认入口为:
1 | |
它和 Swagger UI 的关系不是:
1 | |
而是:
1 | |
两者只是对同一份 OpenAPI Specification 的不同展示和交互方式。SpringDoc v2/v3 官方文档已经同时列出了 Swagger UI 和 Scalar 支持。
Actuator 与独立管理端口
很多生产系统会把:
1 | |
和:
1 | |
分开。
例如:
1 | |
SpringDoc 支持把 OpenAPI 和 Swagger UI 暴露在 management port:
1 | |
这时可以通过类似:
1 | |
访问文档。
这种架构特别适合:
1 | |
这样就不需要为了接口文档,把 Swagger UI 直接暴露给公网。
生产环境是否应该开启 Swagger
默认情况下:
1 | |
SpringDoc 官方分别提供了关闭 API Docs 和 Swagger UI 的配置。
生产环境可以使用:
1 | |
例如:
1 | |
开发环境:
1 | |
生产环境:
1 | |
这里需要区分两件事情:
1 | |
控制 OpenAPI JSON/YAML。
1 | |
控制 UI。
如果:
1 | |
虽然 Swagger UI 页面资源可能存在,但它没有 OpenAPI Specification 可以读取,自然无法正常展示接口。早期 Spring Boot 3 实践文档也特别强调 Swagger UI 依赖 OpenAPI Docs endpoint。
生产环境到底采取哪种方案,建议根据系统情况选择:
1 | |
对于微服务系统,通常没有必要让几十个微服务各自在公网暴露 Swagger UI。
微服务中的接口文档聚合
如果系统包含:
1 | |
每个服务都可以生成自己的:
1 | |
然后由统一文档门户进行聚合:
flowchart LR
A["user-service<br/>/v3/api-docs"]
B["order-service<br/>/v3/api-docs"]
C["payment-service<br/>/v3/api-docs"]
D["inventory-service<br/>/v3/api-docs"]
E["API Gateway / Doc Portal"]
F["统一 API 文档"]
A --> E
B --> E
C --> E
D --> E
E --> F
Swagger UI 本身也支持配置多个外部 OpenAPI URL,SpringDoc 提供 springdoc.swagger-ui.urls.* 用于聚合外部 Specification。
这种情况下,服务本身真正应该维护的是:
1 | |
而不是:
1 | |
这也是理解 SpringDoc 时一个很关键的转变。
Spring MVC Functional Endpoint 与 WebFlux Functional Endpoint
SpringDoc 不只支持:
1 | |
也支持 Spring MVC/WebFlux Functional Endpoint。
例如:
1 | |
也可以使用:
1 | |
或:
1 | |
描述 Functional Endpoint。
SpringDoc 官方提醒,@RouterOperation 场景中 operationId 非常重要,因为框架需要准确定位对应 Route。
所以 SpringDoc 的能力范围已经不只是传统 MVC Controller,而覆盖:
1 | |
构建阶段生成 OpenAPI
OpenAPI 不一定只能在应用运行以后访问:
1 | |
SpringDoc 还提供 Maven/Gradle Plugin,可以在构建流程中生成 JSON/YAML 文档。
SpringDoc Maven Plugin 可以和 Spring Boot Maven Plugin 配合,在 integration-test 生命周期中生成 OpenAPI;官方示例可以通过:
1 | |
触发。
这样 CI 可以变成:
flowchart LR
A["git push"]
B["Maven Build"]
C["启动测试应用"]
D["生成 openapi.json"]
E["API Contract Check"]
F["生成 SDK"]
G["发布制品"]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
这时 OpenAPI 就开始从“方便前端调接口的页面”,升级为软件工程中的正式制品。
例如可以用于:
- API Breaking Change 检查;
- 自动生成 Java/TypeScript SDK;
- Mock Server;
- Contract Test;
- API Gateway 导入;
- API Portal;
- 自动化测试。
这比单纯“项目里装个 Swagger”更接近 OpenAPI 的真正价值。
从 Springfox 迁移
假设旧项目原来使用:
1 | |
迁移后:
1 | |
模型:
1 | |
变成:
1 | |
如果原来:
1 | |
迁移为:
1 | |
SpringDoc 官方迁移指南已经给出了这一套对应关系。
迁移时最好不要采取:
1 | |
再慢慢换注解。
更合理的是:
1 | |
这样依赖关系更干净,也更容易定位问题。
常见问题与排查
/swagger-ui.html 打不开
先不要急着怀疑 Swagger UI。
按照下面的顺序排查:
1 | |
首先访问:
1 | |
如果这个地址都不存在,问题一般不在 Swagger UI 页面。
Spring Security 返回 401 / 403
检查:
1 | |
如果生产环境本来就不应该开放,则不要为了“修好 Swagger”盲目放开权限。
Controller 没有出现在文档中
如果使用的是:
1 | |
但没有:
1 | |
SpringDoc 默认可能不会把它识别为 REST Controller。
推荐使用:
1 | |
SpringDoc 官方 FAQ 对这一行为有明确说明。
DTO 参数没有展开
对于 Query Object:
1 | |
可以尝试:
1 | |
并确保对象有标准 Getter。
Spring Boot 3.2 之后参数名缺失
Spring Boot 3.2 的 Parameter Name Discovery 变化可能导致生成的 OpenAPI 中部分参数信息缺失。
SpringDoc 官方建议让 Java 编译器保留方法参数名称:
1 | |
也就是启用 Java:
1 | |
如果遇到:
1 | |
或者 Path/Query Parameter 名称无法正常识别,这一项值得优先检查。
自定义 HttpMessageConverter 后 Swagger UI 无法解析文档
如果项目自己完全覆盖了 Spring Boot 默认 HttpMessageConverter,可能破坏 SpringDoc 文档响应。
SpringDoc 官方特别指出,应保留:
1 | |
例如:
1 | |
而且 converter 顺序也会影响行为。
所以遇到:
1 | |
不要只检查 Swagger 注解。
如果项目改过:
1 | |
这个地方应该重点检查。
Swagger UI 能开,但没有任何 API
检查:
1 | |
例如:
1 | |
但 Controller 实际在:
1 | |
SpringDoc 自然扫描不到。
Swagger UI 页面存在,但 Fetch /v3/api-docs 失败
检查是不是写了:
1 | |
Swagger UI 的数据源就是 OpenAPI JSON。
没有 /v3/api-docs,UI 就只剩一个壳。
JWT 无法在 Swagger UI 中发送
不要写:
1 | |
OpenAPI 规范专门使用 Security Scheme 表达 Authorization,SpringDoc 官方也推荐 @SecurityRequirement + Bearer Security Scheme。
正确模型应该是:
1 | |
而不是普通 Header Parameter。
版本升级后突然报错
优先检查三件事:
1 | |
不要看到:
1 | |
就先开始修改 Controller。
这种错误非常可能来自版本不兼容。
SpringDoc 的缓存机制
SpringDoc 默认会计算 OpenAPI Definition 并缓存结果。
官方属性:
1 | |
如果设置:
1 | |
则可以关闭 OpenAPI Cache。官方说明,默认情况下 OpenAPI 描述会计算一次并缓存;在某些内部/外部代理场景中,可能需要每次请求重新计算 Server URL。
正常项目不要为了“保证最新”随便关缓存。
Controller 和 DTO 本身不会在应用运行过程中不断发生变化,关闭缓存只会增加没有必要的文档生成开销。
开发期热更新场景另当别论。
接口文档应该写到什么程度
有了 Swagger 注解之后,另一个常见问题是:注解写得太多。
例如:
1 | |
这是无效信息。
又例如:
1 | |
重点也不应该是告诉读者:
1 | |
因为 Schema 本来就能推断。
真正有价值的是:
1 | |
接口文档应该补充的是代码无法直接表达的语义。
可以用一个简单原则判断:
删除这段 Swagger 注解之后,消费者是否会失去重要业务信息?
如果不会,那这段注解大概率没有必要。
推荐的注解职责划分
一个比较合理的工程规范可以是:
| 层级 | 推荐内容 |
|---|---|
| Controller | @Tag |
| API Method | @Operation |
| Path/Query/Header | 必要时使用 @Parameter |
| DTO / VO | @Schema |
| Validation | Bean Validation |
| HTTP Response | @ApiResponse |
| Authentication | @SecurityScheme / @SecurityRequirement |
| API Group | GroupedOpenApi |
| 全局元数据 | OpenAPI Bean |
避免:
1 | |
也避免:
1 | |
一个更适合实际项目的配置结构
对于中大型 Spring Boot 项目,可以把 OpenAPI 配置集中在:
1 | |
例如:
1 | |
业务代码:
1 | |
只关心:
1 | |
数据模型:
1 | |
只负责:
1 | |
这样文档配置不会反过来污染业务代码结构。
API 文档不应该成为第二套类型系统
一些项目为了 Swagger 会出现大量这种代码:
1 | |
1 | |
SpringDoc 本身已经能够从 Java 类型推断这些内容。
如果你的 Java 字段已经是:
1 | |
就没有必要再重复告诉 SpringDoc:
1 | |
更加值得描述的是:
1 | |
接口文档应该增强代码语义,而不是复制代码事实。
OpenAPI 可以成为服务契约
如果只是把 SpringDoc 理解为:
“给前端看接口的 Swagger 页面。”
会低估 OpenAPI 的价值。
一旦系统建立:
1 | |
这份文件就可以继续进入工程链路:
flowchart TD
A["Spring Boot API"]
B["SpringDoc"]
C["openapi.json"]
D["Swagger UI"]
E["API Portal"]
F["SDK Generator"]
G["Contract Test"]
H["Breaking Change Check"]
I["API Gateway"]
J["Mock Server"]
A --> B
B --> C
C --> D
C --> E
C --> F
C --> G
C --> H
C --> I
C --> J
这才是成熟项目中更值得建立的目标:
1 | |
而不是:
1 | |
2026 年之后的 SpringDoc 演进
SpringDoc 现在已经不再只有传统 Swagger UI。
当前官方文档同时提供:
- Swagger UI;
- Scalar;
- Spring MVC;
- WebFlux;
- Spring Security;
- Actuator;
- GraalVM Native Image;
- OpenAPI 3;
- Spring Boot 4;
- MCP 集成。
SpringDoc 3.x 已经进入 Spring Boot 4 时代,当前官方首页使用 3.x starter,并提供面向 Spring Boot 4 的文档;Spring Boot 3 则继续保留独立的 v2 文档。
SpringDoc 3.x 当前还增加了 MCP 模块,可以把已有 REST API 基于 OpenAPI 映射为 AI Tool。
这说明 OpenAPI 在今天的价值已经不仅仅是:
1 | |
它正在逐渐成为:
1 | |
因此从长期工程视角看,比“选择 Swagger UI 还是 Scalar”更重要的问题是:
你的 API 是否拥有准确、稳定、机器可读、可以持续演进的契约。
推荐的工程实践
综合 SpringDoc 的能力和实际项目维护成本,可以采用下面这套原则:
- Spring Boot 3 使用 SpringDoc 2.x,Spring Boot 4 使用 SpringDoc 3.x,不要跨主版本随意组合。当前版本变化较快,应优先检查官方发布说明和实际 Boot 版本。
- Spring MVC 使用
springdoc-openapi-starter-webmvc-*,WebFlux 使用springdoc-openapi-starter-webflux-*。 - Controller 负责
@Tag、@Operation等接口语义,不要用 OpenAPI 注解重复 Spring MVC 已经能够表达的信息。 - DTO 使用
@Schema描述业务语义,数据约束仍然交给 Bean Validation。 - 使用
OpenAPIBean 管理全局元数据和 Security Scheme。 - JWT、OAuth2 等认证使用 OpenAPI Security Scheme,不要把 Authorization 当普通 Header 参数处理。
- 大型系统使用
GroupedOpenApi按业务域拆分 API。 - Spring Security 环境下明确规划 Swagger/OpenAPI endpoint 的访问策略。
- 开发环境可以开放 Swagger UI,生产环境根据安全要求关闭、限制内网访问或迁移至 Management Port。
- 微服务更应该维护
/v3/api-docs这份 API Contract,而不是依赖每个服务各自的 Swagger 页面。 - 将 OpenAPI JSON/YAML 纳入 CI,可以进一步实现 Breaking Change 检查、SDK 生成、Mock、Contract Test 等能力。
- 升级 Spring Boot 时同时检查 SpringDoc 兼容关系,不要把接口文档组件当作完全独立的普通工具依赖。
总结
SpringDoc 的真正价值,不是给 Spring Boot 项目增加一个 Swagger 页面,而是把真实的 Spring Web 接口结构转换为标准 OpenAPI Contract。
整个体系可以概括为:
1 | |
对于 Spring Boot 3 项目,当前应以 SpringDoc 2.x starter 体系为基础;进入 Spring Boot 4 后,则切换到 SpringDoc 3.x。SpringDoc 可以从 Controller、请求参数、DTO、Validation 和 OpenAPI 注解中生成绝大部分接口结构,开发者真正需要维护的应该是代码无法自动推断出的业务语义。
当接口数量较少时,它只是减少手工写文档的工作;当系统进入模块化单体、微服务、API Gateway、SDK 自动生成和契约测试阶段后,OpenAPI 则可以逐渐成为整个服务体系中的正式接口契约。到了这个阶段,Swagger UI 只是其中一个查看入口,而不再是 API 文档本身。