做后端开发,接口文档几乎绕不开。传统做法是在项目里单独维护一份 Word 或者 Markdown 文档,接口一多、需求一改,文档就和代码脱节了,前端同事照着旧文档调接口,报错了才发现在害人害己。Swagger 解决的就是这个问题:它根据代码里的注解自动渲染出一份可视化的接口文档,代码改了文档跟着变,还能在页面上直接调试接口。这篇文章以 Spring Boot 项目为例,完整讲一下如何用 springdoc-openapi 整合 OpenAPI 3 规范,从引入依赖到注解配置再到分组与权限控制,一次性说清楚。

一、为什么选择 springdoc-openapi 而不是 springfox
老一点的 Spring Boot 项目里,Swagger 整合基本都用 springfox 这个库。但 springfox 有一个致命问题:它的最后一个稳定版本 3.0.0 发布后基本停止维护了,对新版 Spring Boot 2.6 以上的支持很差。因为 Spring Boot 2.6 开始默认把路径匹配策略改成了 PathPatternParser,而 springfox 依赖的 AntPathMatcher 与之冲突,启动时会直接抛出 NullPointerException,很多开发者不得不额外配置 spring.mvc.pathmatch.matching-strategy=ant_path_matcher 来绕过,这本质上是在开倒车。
springdoc-openapi 是社区目前主推的替代方案,它原生支持 OpenAPI 3 规范(springfox 主要停留在 Swagger 2 / OpenAPI 2),对新版本的 Spring Boot 和 Spring WebFlux 都有良好支持,而且配置更简单,常用功能开箱即用,不需要像 springfox 那样写一大堆 Docket 配置。对于新项目,直接选 springdoc-openapi 就对了。
两者的核心区别在于数据格式:Swagger 2 使用 JSON 描述接口,而 OpenAPI 3 规范更完善,支持一个接口多种请求体类型、更丰富的 Schema 定义。目前主流的 API 网关、Mock 工具、代码生成器(比如 openapi-generator)都已经全面拥抱 OpenAPI 3,跟着规范走,生态兼容性会好很多。
二、引入依赖与基础配置
以 Spring Boot 2.7.x 为例,在 pom.xml 中加入如下依赖即可:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>注意版本匹配:Spring Boot 2.x 要用 springdoc-openapi 1.x 系列,访问路径是 /swagger-ui.html;如果是 Spring Boot 3.x,则要换成 springdoc-openapi-starter-webmvc-ui(2.x 系列),并且 UI 路径变成了 /swagger-ui/index.html。这个版本对应关系搞错了,页面会直接 404,是新手最常踩的坑之一。
引入依赖后不做任何配置,启动项目就能看到文档了,Controller 里的接口会自动被扫描出来。当然一般我们会补充一些全局信息,通过一个配置类来实现:
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().info(new Info()
.title("订单系统接口文档")
.version("1.0")
.description("提供订单、商品相关的全部 REST 接口")
.contact(new Contact().name("后端团队").email("dev@ipipp.com")));
}
}另外也可以在 application.yml 里做精细控制,常用的几个配置项如下:
springdoc:
api-docs:
enabled: true # 是否开启 /v3/api-docs 端点
path: /v3/api-docs # 接口描述 JSON 的路径
swagger-ui:
enabled: true
path: /swagger-ui.html
packages-to-scan: com.example.order.controller # 限定扫描包,避免把非接口类扫进来packages-to-scan 这个配置很有用,项目规模大了以后,如果不对扫描范围加以限制,一些内部的工具 Controller 也会出现在文档里,既混乱又不安全。
三、常用注解详解与示例
自动扫描只能拿到接口路径和参数类型,要让文档真正可读,还得靠注解补充描述。OpenAPI 3 的注解都在 io.swagger.v3.oas.annotations 包下,和 Swagger 2 的注解完全是两套体系,迁移时注意逐个替换。下面通过一个完整的 Controller 示例来看最常用的几个注解:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@Tag(name = "订单管理", description = "订单的创建、查询与取消")
@RestController
@RequestMapping("/api/order")
public class OrderController {
@Operation(summary = "根据ID查询订单", description = "返回订单的完整信息,包括商品明细")
@GetMapping("/{id}")
public OrderVO getOrder(
@Parameter(description = "订单ID", example = "10001")
@PathVariable Long id) {
return orderService.getById(id);
}
@Operation(summary = "创建订单")
@PostMapping
public Long createOrder(@RequestBody OrderCreateDTO dto) {
return orderService.create(dto);
}
}注解的职责可以这样理解:@Tag 用在类上做接口分组,页面上左侧菜单按它归类;@Operation 用在方法上,summary 是接口名,description 是详细说明;@Parameter 描述单个参数。对于 @RequestBody 的实体类,则要在 DTO 上用 @Schema 注解:
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
@Schema(description = "创建订单的请求参数")
public class OrderCreateDTO {
@Schema(description = "商品ID", example = "88", requiredMode = Schema.RequiredMode.REQUIRED)
private Long productId;
@Schema(description = "购买数量", example = "2", minimum = "1")
private Integer quantity;
@Schema(description = "订单金额", example = "199.00")
private BigDecimal amount;
// 省略 getter/setter
}这里有个细节要提一下:字段上如果加了 JSR-303 校验注解(比如 @NotNull、@Min(1)),springdoc 会自动把它们体现在文档的必填标记和取值范围上,不需要重复声明。所以建议 DTO 该加校验注解就加,一举两得。另外,统一返回结果类(比如 Result<T> 这种泛型包装)建议配合 @Schema 的 implementations 属性明确指定泛型类型,否则文档里的响应结构会丢失泛型信息,显示成 Object。
四、接口分组与生产环境安全控制
项目里如果同时存在后台管理接口和面向 App 的接口,全部堆在一个文档页面会很难找。springdoc 提供了 GroupedOpenApi 支持按路径或包拆分多个分组:
import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GroupConfig {
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("后台管理")
.pathsToMatch("/api/admin/**")
.build();
}
@Bean
public GroupedOpenApi appApi() {
return GroupedOpenApi.builder()
.group("移动端")
.pathsToMatch("/api/app/**")
.build();
}
}配置完成后,Swagger UI 页面右上角会出现分组下拉框,前端同事可以按需切换,体验提升明显。
还有一个容易被忽视的问题是安全。Swagger 页面本身是一个暴露所有接口细节的入口,如果生产环境不加控制地开放,等于把系统的接口清单拱手送给别人,攻击者能很方便地找到未做鉴权的接口。推荐的做法是分环境配置:开发环境开启,生产环境关闭,通过 Maven profile 或配置中心的变量来控制:
springdoc:
api-docs:
enabled: ${swagger.enabled:false}
swagger-ui:
enabled: ${swagger.enabled:false}这样只有当 swagger.enabled 显式设为 true 时文档才可用,生产环境的配置里不设置这个变量即可。如果确实需要在测试环境保留文档,同时又要防止任意访问,可以结合 Spring Security 对 /swagger-ui/** 和 /v3/api-docs/** 路径做认证拦截,只放行内部网段或指定账号。
最后补充一个小技巧:springdoc 默认生成的界面是英文的,如果希望汉化,可以自行下载 swagger-ui 的静态资源放入项目的 src/main/resources/META-INF/resources/webjars/ 目录下覆盖默认文件,并修改其中的文案。对于内部团队使用来说,这个工作量不大,但对文档的可读性帮助不小。整体来看,用 springdoc-openapi 整合 OpenAPI 3 的成本非常低,基本就是加依赖、写注解两步,换来的是文档与代码永远一致,这笔账怎么算都划算。
Spring BootSwaggerOpenAPI 3接口文档修改时间:2026-09-09 09:31:08