很多开发者习惯将 SpringDoc OpenAPI 3 称为 Swagger 3,它是 Swagger 2 的下一代规范实现。
要理解这套技术栈,我们需要理清几个核心概念的关系:
OpenAPI 规范:是一种用于描述 REST API 的行业标准,它定义了接口的路径、参数、响应等标准化结构,让不同的工具可以基于这套规范生成文档、客户端代码等。
Swagger:是一套实现了 OpenAPI 规范的工具集,它可以根据代码中的注解自动生成接口文档,同时提供在线调试功能。
SpringDoc:是 Spring 生态中用于集成 OpenAPI 规范的官方推荐组件,它替代了已经停止维护的 SpringFox(旧 Swagger 2 的 Spring 集成组件),完美适配 Spring Boot 3 的新特性。
Knife4j:是一款基于 Swagger / OpenAPI 的开源增强 UI 插件,它提供了比原生 Swagger UI 更美观、更易用的界面,同时增加了很多实用的增强功能。
在前后端分离的开发模式下,传统的手写接口文档已经无法满足高效开发的需求,它存在很多痛点:
文档更新不及时:代码修改后,文档往往无法同步更新,导致前后端联调时出现信息不一致的问题。
沟通成本高:前后端开发人员需要反复确认接口参数、返回值、状态码等信息,浪费大量时间。
调试效率低:开发人员需要额外使用 Postman 等工具来调试接口,手动填写参数、构造请求,效率低下。
而集成 Swagger 3 可以完美解决这些问题:
自动同步文档:接口文档会根据代码中的注解自动生成,代码修改后,文档会自动更新,彻底解决文档过时的问题。
在线调试功能:开发者可以直接在文档页面中调试接口,自动填充参数,发送请求并查看响应结果,无需额外的调试工具。
标准化规范:生成的文档完全符合 OpenAPI 规范,可以被 Postman、API 网关等多种工具直接导入,实现生态互通。
增强体验:配合 Knife4j 美化插件,我们可以获得更友好的界面,以及离线文档导出、接口排序、自定义文档等增强功能,大幅提升开发体验。
在开始集成前,请确认你的项目满足以下基础要求:
Spring Boot 3.x 版本(最低支持 3.0 版本)
JDK 17+(Spring Boot 3 的基础运行要求)
Maven 或 Gradle 构建工具
我们只需要引入 Knife4j 的适配 Spring Boot 3 的 starter 即可,它已经内置了 SpringDoc OpenAPI 的所有依赖,无需额外引入其他包,同时完美适配了 Jakarta EE 的包名变更。
在 pom.xml 中添加以下依赖:
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>接下来在 application.yml 中添加基础配置,用于配置接口扫描、文档展示等基础信息:
springdoc:
# Swagger UI 相关配置
swagger-ui:
path: /swagger-ui.html
# 标签按字母顺序排序
tags-sorter: alpha
# 接口按字母顺序排序
operations-sorter: alpha
# API 文档元数据接口路径
api-docs:
path: /v3/api-docs
# 分组配置,这里先配置默认分组
group-configs:
- group: 'default'
# 匹配所有路径
paths-to-match: '/**'
# 扫描 Controller 所在的包,替换为你自己的包路径
packages-to-scan: com.example.demo.controller
# Knife4j 增强配置
knife4j:
# 开启 Knife4j 增强功能
enable: true
# 基础配置
setting:
# 设置界面语言为中文
language: zh_cn
# 开启调试功能
enable-debug: true我们可以通过配置类来自定义文档的基础信息,比如文档标题、版本、作者描述等,创建一个配置类:
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("示例系统接口文档")
.version("1.0.0")
.description("这是一个示例系统的接口文档,包含用户管理、订单管理等模块的接口说明")
.contact(new Contact()
.name("开发团队")
.email("dev@example.com")));
}
}如果你的项目比较大,包含多个业务模块,我们可以将接口按模块进行分组,方便开发者查看。我们可以通过配置类来实现多分组:
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GroupConfig {
/**
* 用户模块分组
*/
@Bean
public GroupedOpenApi userGroup() {
return GroupedOpenApi.builder()
.group("用户管理模块")
.pathsToMatch("/api/user/**")
.packagesToScan("com.example.demo.controller.user")
.build();
}
/**
* 订单模块分组
*/
@Bean
public GroupedOpenApi orderGroup() {
return GroupedOpenApi.builder()
.group("订单管理模块")
.pathsToMatch("/api/order/**")
.packagesToScan("com.example.demo.controller.order")
.build();
}
}接下来我们编写一个简单的业务代码,来演示注解的使用:
首先是用户实体类:
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "用户信息实体")
public class User {
@Schema(description = "用户 ID", example = "1001")
private Long id;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "zhangsan")
private String username;
@Schema(description = "用户年龄", example = "25")
private Integer age;
@Schema(description = "用户邮箱", example = "zhangsan@example.com")
private String email;
}然后是用户 Controller:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/user")
@Tag(name = "用户管理模块", description = "用户的增删改查相关接口")
public class UserController {
private final List<User> userList = new ArrayList<>();
public UserController() {
// 初始化测试数据
User user = new User();
user.setId(1L);
user.setUsername("test");
user.setAge(20);
user.setEmail("test@example.com");
userList.add(user);
}
@Operation(summary = "根据 ID 查询用户", description = "传入用户 ID,返回对应的用户详细信息")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "查询成功"),
@ApiResponse(responseCode = "404", description = "用户不存在")
})
@GetMapping("/{id}")
public User getUserById(
@Parameter(description = "用户 ID", required = true, example = "1")
@PathVariable Long id) {
return userList.stream()
.filter(user -> user.getId().equals(id))
.findFirst()
.orElse(null);
}
@Operation(summary = "创建用户", description = "创建新的用户,返回创建后的用户信息")
@PostMapping
public User createUser(@RequestBody User user) {
userList.add(user);
return user;
}
@Operation(summary = "查询所有用户", description = "返回系统中所有的用户列表")
@GetMapping
public List<User> getAllUsers() {
return userList;
}
}完成以上配置后,启动项目,在浏览器中访问以下地址即可查看接口文档:
http://localhost:8080/doc.html原生的 Swagger UI 界面比较简陋,功能也比较基础,而 Knife4j 作为一款增强美化插件,完美解决了这个问题,它提供了很多实用的增强功能:
更美观的界面设计,符合国内开发者的使用习惯
左侧菜单分组展示,支持接口排序,方便查找接口
离线文档导出,支持 Markdown、Word、Html 等多种格式的文档导出
接口调试增强,支持动态参数、参数缓存、自定义脚本等功能
支持自定义文档,你可以添加额外的 Markdown 文档来补充接口说明
生产环境屏蔽,保护接口文档不被暴露在公网
Knife4j 提供了丰富的个性化配置,你可以根据自己的需求进行调整
knife4j:
enable: true
# 开启生产环境保护,生产环境下会自动屏蔽文档访问
production: false
# 开启基础认证,保护文档不被随意访问
basic:
enable: false
username: admin
password: 123456
# 个性化 UI 配置
setting:
language: zh_cn
# 是否显示实体类列表
enable-swagger-models: true
swagger-model-name: 实体类列表
# 是否显示版本信息
enable-version: false
# 开启请求参数缓存
enable-request-cache: true
# 是否开启调试功能
enable-debug: true
# 是否开启接口分组功能
enable-group: true
# 自定义页脚内容
enable-footer-custom: true
footer-custom-content: Apache License 2.0 | Copyright 2025 示例团队接口文档包含了系统的所有接口信息,属于敏感信息,绝对不能在生产环境暴露。我们可以通过以下配置来实现生产环境的文档关闭,做到「双重锁定」。在生产环境的配置文件 application-prod.yml 中添加以下配置:
knife4j:
# 开启增强功能
enable: true
# 开启生产环境屏蔽,界面会提示文档已禁用
production: true
springdoc:
# 彻底关闭 API 文档元数据接口
api-docs:
enabled: false
# 彻底关闭原生 Swagger UI
swagger-ui:
enabled: false这样配置后,生产环境下就无法访问接口文档了,彻底避免了敏感信息的泄露。
Swagger 3 通过注解来描述接口信息,以下是核心常用注解的详细说明和使用案例:
模块分组注解
这个注解用于标记 Controller 类,用于接口的分组展示,对应旧 Swagger 2 中的 @Api 注解。
作用范围:Controller 类 常用属性:
name:分组名称,会显示在左侧的菜单中
description:分组的详细描述
使用案例:
@Tag(name = "用户管理模块", description = "用户的增删改查相关接口")
@RestController
@RequestMapping("/api/user")
public class UserController {
// ...
}接口描述注解
这个注解用于描述单个接口的功能,对应旧 Swagger 2 中的 @ApiOperation 注解。
作用范围:Controller 方法 常用属性:
summary:接口的简短描述,会显示在接口列表中
description:接口的详细描述
hidden:是否隐藏该接口,默认 false
使用案例:
@Operation(
summary = "根据 ID 查询用户",
description = "传入用户 ID,返回对应的用户详细信息"
)
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// ...
}响应状态注解
这两个注解用于描述接口的响应状态码和说明,对应旧 Swagger 2 中的同名注解。
作用范围:Controller 方法 常用属性:
responseCode:HTTP 响应状态码
description:该状态码的说明
使用案例:
@ApiResponses({
@ApiResponse(responseCode = "200", description = "查询成功"),
@ApiResponse(responseCode = "404", description = "用户不存在"),
@ApiResponse(responseCode = "500", description = "服务器内部异常")
})
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// ...
}参数描述注解
这个注解用于描述接口的参数,对应旧 Swagger 2 中的 @ApiParam 注解。
作用范围:方法参数 常用属性:
description:参数的描述信息
required:是否为必填参数
example:参数的示例值
hidden:是否隐藏该参数
使用案例:
@GetMapping("/{id}")
public User getUserById(
@Parameter(description = "用户 ID", required = true, example = "1")
@PathVariable Long id) {
// ...
}实体类注解
这个注解用于描述实体类和实体类的字段,对应旧 Swagger 2 中的 @ApiModel 和 @ApiModelProperty 注解。
作用范围:实体类、实体类字段 常用属性:
description:实体或字段的描述信息
example:字段的示例值
requiredMode:是否为必填字段
hidden:是否隐藏该字段
使用案例:
@Schema(description = "用户信息实体")
public class User {
@Schema(description = "用户 ID", example = "1001")
private Long id;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "zhangsan")
private String username;
}隐藏注解
这个注解用于隐藏不需要在文档中显示的接口、参数或字段,比如一些内部接口,不需要对外暴露。
作用范围:类、方法、参数、字段 使用案例:
// 隐藏整个内部接口 Controller
@Hidden
@RestController
@RequestMapping("/internal")
public class InternalController {
// ...
}
// 隐藏单个接口
@Hidden
@GetMapping("/internal/test")
public String test() {
return "test";
}问题原因:
引入了错误的依赖,比如使用了旧版本的 Knife4j 依赖,没有适配 Spring Boot 3 的 Jakarta 包名
访问路径错误,混淆了原生 Swagger UI 和 Knife4j 的访问路径
解决方案:
确认依赖为 knife4j-openapi3-jakarta-spring-boot-starter,而不是旧的适配 Spring Boot 2 的依赖
确认访问路径为 http://localhost:port/doc.html,如果是原生 Swagger UI,访问路径为 http://localhost:port/swagger-ui.html
问题原因: 项目中集成了 Spring Security,安全框架拦截了文档相关的路径,导致无法访问。
解决方案: 在 Spring Security 的配置类中,将文档相关的路径加入白名单,配置示例:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
// 放行文档相关的路径
.requestMatchers(
"/doc.html",
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/webjars/**"
).permitAll()
// 其他接口的认证配置
.anyRequest().authenticated()
);
return http.build();
}问题原因:
扫描包配置错误,Controller 不在配置的扫描包路径下
Controller 没有添加 @RestController 或 @RequestMapping 注解
路径匹配策略导致接口无法被扫描到
解决方案:
检查 packages-to-scan 配置,确认 Controller 所在的包被正确扫描
确认 Controller 类添加了 @RestController 注解
如果遇到路径匹配问题,可以尝试调整路径匹配策略:
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher问题原因: 依赖冲突,比如同时引入了旧的 SpringFox 依赖和 SpringDoc 依赖,或者依赖版本不兼容。
解决方案: 清理项目中的旧依赖,删除 SpringFox 相关的依赖,只保留 Knife4j 的 starter 依赖,然后刷新 Maven 依赖重新构建。
问题原因: 没有在生产环境关闭文档的配置,导致文档被暴露在公网。
解决方案: 按照之前的生产环境配置,在生产环境的配置文件中关闭文档的相关配置,做到双重锁定,避免敏感信息泄露。