源本科技 | 码上会

Spring Boot 集成 Swagger

2026/04/04
2
0

什么是 Swagger 3

很多开发者习惯将 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 更美观、更易用的界面,同时增加了很多实用的增强功能。

https://www.openapis.org/https://springdoc.org/

为什么要集成接口文档

在前后端分离的开发模式下,传统的手写接口文档已经无法满足高效开发的需求,它存在很多痛点:

  • 文档更新不及时:代码修改后,文档往往无法同步更新,导致前后端联调时出现信息不一致的问题。

  • 沟通成本高:前后端开发人员需要反复确认接口参数、返回值、状态码等信息,浪费大量时间。

  • 调试效率低:开发人员需要额外使用 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 通过注解来描述接口信息,以下是核心常用注解的详细说明和使用案例:

@Tag

模块分组注解

这个注解用于标记 Controller 类,用于接口的分组展示,对应旧 Swagger 2 中的 @Api 注解。

作用范围:Controller 类 常用属性

  • name:分组名称,会显示在左侧的菜单中

  • description:分组的详细描述

使用案例

@Tag(name = "用户管理模块", description = "用户的增删改查相关接口")
@RestController
@RequestMapping("/api/user")
public class UserController {
    // ...
}

@Operation

接口描述注解

这个注解用于描述单个接口的功能,对应旧 Swagger 2 中的 @ApiOperation 注解。

作用范围:Controller 方法 常用属性

  • summary:接口的简短描述,会显示在接口列表中

  • description:接口的详细描述

  • hidden:是否隐藏该接口,默认 false

使用案例

@Operation(
    summary = "根据 ID 查询用户",
    description = "传入用户 ID,返回对应的用户详细信息"
)
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
    // ...
}

@ApiResponse / @ApiResponses

响应状态注解

这两个注解用于描述接口的响应状态码和说明,对应旧 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) {
    // ...
}

@Parameter

参数描述注解

这个注解用于描述接口的参数,对应旧 Swagger 2 中的 @ApiParam 注解。

作用范围:方法参数 常用属性

  • description:参数的描述信息

  • required:是否为必填参数

  • example:参数的示例值

  • hidden:是否隐藏该参数

使用案例

@GetMapping("/{id}")
public User getUserById(
        @Parameter(description = "用户 ID", required = true, example = "1")
        @PathVariable Long id) {
    // ...
}

@Schema

实体类注解

这个注解用于描述实体类和实体类的字段,对应旧 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;
}

@Hidden

隐藏注解

这个注解用于隐藏不需要在文档中显示的接口、参数或字段,比如一些内部接口,不需要对外暴露。

作用范围:类、方法、参数、字段 使用案例

// 隐藏整个内部接口 Controller
@Hidden
@RestController
@RequestMapping("/internal")
public class InternalController {
    // ...
}

// 隐藏单个接口
@Hidden
@GetMapping("/internal/test")
public String test() {
    return "test";
}

常见问题

404

问题原因

  • 引入了错误的依赖,比如使用了旧版本的 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

Unauthorized 或 403

问题原因: 项目中集成了 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 依赖重新构建。

生产环境暴露文档

问题原因: 没有在生产环境关闭文档的配置,导致文档被暴露在公网。

解决方案: 按照之前的生产环境配置,在生产环境的配置文件中关闭文档的相关配置,做到双重锁定,避免敏感信息泄露。