Swagger3详解

792 阅读9分钟

一,介绍

Swagger 3 通常指的是 OpenAPI 3.0 及更高版本,它是一个开放的API描述规范,用于标准化RESTful API的设计、文档化和测试。通过编写符合OpenAPI规范的YAML或JSON文件,开发者可以清晰地定义API的接口、参数、返回值、鉴权方式等细节,并自动生成交互式文档、客户端/服务端代码,甚至进行接口测试。


核心功能与价值

  1. 标准化设计:统一API描述格式,避免团队协作中的沟通歧义。
  2. 自动生成文档:通过工具(如Swagger UI)生成可视化、可交互的API文档。
  3. 代码生成:根据规范自动生成服务端和客户端代码(支持多种语言)。
  4. 接口测试:结合工具(如Postman、Swagger Inspector)直接调试API。
  5. 生态支持:与主流开发框架(Spring Boot、FastAPI等)深度集成。

发展历程

  1. Swagger的诞生(2011-2015)
  • 2011年:由Tony Tam等人开发,最初是Wordnik公司的API框架(Scala语言)的副产品,目的是解决API文档维护问题。
  • 2011-2014年:推出Swagger 1.x,逐渐成为最流行的API文档工具之一。
  • 2014年:发布Swagger 2.0,规范更简洁,工具生态(Swagger UI、Swagger Editor等)成熟。
  1. 转型为OpenAPI(2015-2017)
  • 2015年:Swagger规范捐赠给Linux基金会,成立OpenAPI Initiative(OAI),联合Google、IBM等大厂共同维护。
  • 2017年:发布OpenAPI 3.0(即Swagger 3),彻底重构规范,支持更复杂的API场景。
  1. OpenAPI 3.x时代(2017至今)
  • 2021年:发布OpenAPI 3.1,兼容JSON Schema 2020-12,进一步强化灵活性和扩展性。
  • 现状:OpenAPI已成为API领域的行业标准,Swagger工具集(如Swagger UI)仍是其生态的重要组成部分。

Swagger与OpenAPI的关系

  • Swagger:指原始规范和工具集(如Swagger UI、Swagger Codegen)。
  • OpenAPI:规范的官方名称,由OAI维护,Swagger工具集支持OpenAPI规范。
  • 常见误解
    • “Swagger 3”是OpenAPI 3.0的非官方叫法。
    • Swagger工具(如Swagger UI)可以解析OpenAPI 2.0/3.x文件。

SpringDoc

Springdoc 是 Spring Boot 应用与 Swagger 3(OpenAPI 3.0+)集成的核心工具,它通过自动化解析 Spring 的注解和代码结构,生成符合 OpenAPI 3.0 规范的 API 文档,并与 Swagger UI 等工具无缝结合。

Springdoc 的作用与定位

  • 核心功能
    • 将 Spring Boot 中的控制器(@RestController)、方法(@GetMapping/@PostMapping 等)和模型(@Schema)自动转换为 OpenAPI 3.0 规范的文档描述(YAML/JSON)。
    • 集成 Swagger UI,提供可视化、交互式的 API 文档界面。
    • 支持 OpenAPI 3.0+ 的高级特性(如多服务器配置、鉴权方案、Webhooks 等)。
  • 与 Swagger 3(OpenAPI 3.0)的关系: Springdoc 是 实现 OpenAPI 3.0 规范的工具,而 Swagger 3 是规范本身。
    • Springdoc 依赖 OpenAPI 3.0 的规则解析代码结构。
    • 最终生成的文档遵循 OpenAPI 3.0 格式,并通过 Swagger UI 展示。

为什么需要 Springdoc?

  • 历史背景: Swagger 早期在 Spring 生态中的实现是 Springfox(支持 Swagger 2.0),但它对 OpenAPI 3.0 的支持滞后且维护不足。 Springdoc 应运而生,专注于 全面支持 OpenAPI 3.0+,且与 Spring Boot 3+ 兼容性更好。
  • 关键优势
    • 零配置启动:仅需添加依赖,即可自动扫描 Spring 控制器生成文档。
    • 注解驱动:通过 @Operation@Parameter@Schema 等注解精细控制文档细节。
    • 与 Spring 生态深度集成:支持 Spring Web MVC、Spring WebFlux、Spring Security 等模块。

与旧版 Springfox 的对比

特性Springdoc(OpenAPI 3.0+)Springfox(Swagger 2.0)
规范支持全面支持 OpenAPI 3.0/3.1仅支持 Swagger 2.0(OpenAPI 2.0)
维护状态活跃维护(GitHub 1k+ stars)已停止维护(官方推荐迁移到 Springdoc)
Spring Boot 3+ 兼容性完全兼容不兼容
配置复杂度更简洁(自动扫描 + 注解驱动)需手动配置 Docket 等对象

二,快速入门

  1. 添加依赖

    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        <version>2.3.0</version> 
    </dependency>
    
  2. 编写第一个接口

    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.Parameter;
    import io.swagger.v3.oas.annotations.tags.Tag;
    
    @RestController
    @Tag(name = "示例接口", description = "简单的问候 API")
    public class HelloController {
    
        @Operation(
            summary = "打招呼",
            description = "根据传入的名称返回问候语",
            parameters = @Parameter(name = "name", description = "用户名称", example = "Alice")
        )
        @GetMapping("/hello")
        public String sayHello(@RequestParam(required = false, defaultValue = "World") String name) {
            return "Hello, " + name + "!";
        }
    }
    
  3. 开启openapi

    # swagger-ui custom path
    springdoc:
      api-docs:
        # 开启Swagger的doc文档
        enabled: true
        path: /docs
      swagger-ui:
        # 启用Swagger UI
        enabled: true
        path: /api-docs
    
  4. 启动应用

    运行 Spring Boot 主类,访问以下 URL:Swagger UI 界面http://localhost:8080/api-docs

三,相关注解

3.1 类级别注解

@Tag

  • 用途:定义接口分组(类似 Swagger 2.0 的 @Api),用于在 Swagger UI 中将多个接口归类到同一标签下。

  • 常用属性

    • name:标签名称(必填,唯一标识)。
    • description:标签描述。
    • externalDocs:附加外部文档链接。
  • 示例

    @RestController
    @Tag(name = "用户管理", description = "用户增删改查接口")
    public class UserController {
        // ...
    }
    

3.2 方法级别注解

@Operation

  • 用途:描述单个接口方法(如 GET、POST)的元数据。
  • 关键属性
    • summary:接口摘要(简洁标题)。
    • description:详细描述。
    • tags:覆盖类级别的 @Tag 分组。
    • parameters:定义接口参数(可与方法参数上的 @Parameter 结合使用)。
    • responses:自定义响应状态码和描述。
  • 示例
    @Operation(
        summary = "创建用户",
        description = "根据传入的 User 对象创建新用户",
        responses = {
            @ApiResponse(responseCode = "201", description = "用户创建成功"),
            @ApiResponse(responseCode = "400", description = "请求参数无效")
        }
    )
    @PostMapping("/users")
    public User createUser(@RequestBody User user) { /* ... */ }
    

@ApiResponses / @ApiResponse

  • 用途:定义接口的响应状态码和说明(通常与 @Operation 配合)。
  • 属性
    • responseCode:HTTP 状态码(如 "200")。
    • description:状态码描述。
    • content:指定响应内容类型和模型(使用 @Content)。
  • 示例
    @Operation(summary = "获取用户详情")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "成功返回用户数据", 
                     content = @Content(schema = @Schema(implementation = User.class))),
        @ApiResponse(responseCode = "404", description = "用户不存在")
    })
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) { /* ... */ }
    

3.3 参数级别注解

@Parameter

  • 用途:描述接口的请求参数(路径参数、查询参数、请求头等)。
  • 关键属性
    • name:参数名(需与代码中的变量名一致)。
    • description:参数说明。
    • required:是否必填(默认 false)。
    • schema:参数的数据类型和约束(如 @Schema)。
    • in:参数位置(path, query, header, cookie)。
  • 示例
    @GetMapping("/search")
    public List<User> searchUsers(
        @Parameter(
            name = "keyword",
            description = "搜索关键词",
            required = true,
            schema = @Schema(type = "string", minLength = 2)
        )
        @RequestParam String keyword,
        @Parameter(
            name = "page",
            description = "分页页码",
            schema = @Schema(type = "integer", minimum = "1", defaultValue = "1")
        )
        @RequestParam(defaultValue = "1") int page
    ) { /* ... */ }
    

@RequestBody

  • 用途:描述请求体的结构和内容(通常与 @Schema 配合)。
  • 示例
    @PostMapping("/users")
    public User createUser(
        @io.swagger.v3.oas.annotations.parameters.RequestBody(
            description = "用户数据",
            required = true,
            content = @Content(
                schema = @Schema(implementation = User.class),
                examples = @ExampleObject(
                    name = "示例请求",
                    value = "{\"name\": \"Alice\", \"age\": 25}"
                )
            )
        )
        @RequestBody User user
    ) { /* ... */ }
    

3.4 模型与字段注解

@Schema

  • 用途:定义数据模型(DTO、实体类)及其字段的元数据。
  • 常用属性
    • title:模型标题。
    • description:详细描述。
    • required:标记必填字段(如 required = true)。
    • example:示例值。
    • type:数据类型(自动推断,通常无需手动指定)。
    • minimum / maximum:数值范围约束。
  • 示例
    @Schema(name = "User", description = "用户实体")
    public class User {
        @Schema(description = "用户ID", example = "1001", minimum = "1")
        private Long id;
    
        @Schema(description = "用户姓名", required = true, minLength = 2)
        private String name;
    
        @Schema(description = "用户年龄", example = "25", minimum = "0", maximum = "150")
        private Integer age;
    }
    

@ArraySchema

  • 用途:描述数组或集合类型的字段。
  • 示例
    @Schema(description = "用户列表")
    @ArraySchema(
        arraySchema = @Schema(description = "用户数组"),
        schema = @Schema(implementation = User.class)
    )
    private List<User> users;
    

3.5 其他注解

@Hidden

  • 用途:隐藏接口、模型或字段,不生成文档。
  • 示例
    @Hidden  // 隐藏整个接口
    @RestController
    public class InternalController { /* ... */ }
    
    public class User {
        @Hidden  // 隐藏敏感字段(如密码)
        private String password;
    }
    

@ExampleObject

  • 用途:为请求或响应提供示例数据。
  • 示例
    @Operation(summary = "创建用户")
    @ApiResponse(
        responseCode = "201",
        content = @Content(
            mediaType = "application/json",
            examples = @ExampleObject(
                name = "成功示例",
                value = "{\"id\": 1, \"name\": \"Alice\"}"
            )
        )
    )
    @PostMapping("/users")
    public User createUser(@RequestBody User user) { /* ... */ }
    

四,配置相关

4.1 基础配置类(OpenAPI 信息)

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("测试 API")//标题
                        .version("1.0.0")//api的版本
                        .description("测试接口文档")//描述信息
                        .contact(new Contact()
                                .name("技术支持")//联系方式等
                                .email("support@example.com"))
                        .license(new License()
                                .name("Apache 2.0")//许可证信息
                                .url("https://www.apache.org/licenses/LICENSE-2.0")));
    }
}

4.2 分组配置

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 userApi() {
        return GroupedOpenApi.builder()
                .group("用户接口")
                .pathsToMatch("/api/user/**")   // 匹配路径规则
                .packagesToScan("com.example.user") // 指定扫描包(可选)
                .build();
    }

    // 管理接口分组
    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
                .group("管理接口")
                .pathsToMatch("/api/admin/**")
                .build();
    }
}

通配符

通配符说明
?匹配单个字符(如 /api/v? 匹配 /api/v1/api/v2,但不匹配 /api/v12
*匹配同一层路径中的任意字符(如 /api/* 匹配 /api/user,不匹配 /api/user/1
**跨路径层级匹配任意字符(如 /api/** 匹配所有以 /api/ 开头的路径)

4.3 使用 Profile 动态加载配置类

通过 @Profile 注解限制 Swagger 配置类仅在非生产环境生效:

@Configuration
@Profile("!prod") // 仅在非生产环境(如 dev、test)生效
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI().info(new Info().title("开发环境 API"));
    }

    @Bean
    public GroupedOpenApi userApi() {
        return GroupedOpenApi.builder()
                .group("用户接口")
                .pathsToMatch("/api/**")
                .build();
    }
}

4.4 接口排序

4.4.1 基础排序规则

Swagger UI 默认的排序规则:

  • 标签(Tags):按接口的 @Tag 名称字母顺序排序。
  • 接口(Operations):按接口路径(Path)字母顺序排序。

4.4.2 通过 YAML 配置排序

application.yml 中配置以下参数,调整排序逻辑:

  1. 按字母顺序排序

    springdoc:
      swagger-ui:
        tags-sorter: alpha       # 标签按字母顺序排序(默认)
        operations-sorter: alpha # 接口按路径字母顺序排序(默认)
    
  2. 按方法排序(GET/POST/PUT/DELETE)

    springdoc:
      swagger-ui:
        operations-sorter: method # 接口按 HTTP 方法排序(GET → POST → PUT → DELETE)
    
  3. 按路径层级排序

    springdoc:
      swagger-ui:
        operations-sorter: path   # 接口按路径层级深度排序(如 /a → /a/b → /a/b/c)
    

五,整合Knife4j框架

5.1 介绍

Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-uiui皮肤项目。

Knife4j不仅仅将前身的Ui皮肤通过Vue技术栈进行了重写,也增加了更多个性化的特性增强功能,基于springfox项目以及OpenAPI的规范

目前主要支持以Java开发为主,并且是依赖于大环境下使用的Spring MVCSpring BootSpring Cloud框架.

5.2 集成Knife4j

  1. 导包

    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
        <version>4.5.0</version>
    </dependency>
    

    注意:knife4j依赖了springdoc,不需要俩个都引入,引入这个一个即可

  2. 编写配置文件

    # Knife4j 增强配置
    knife4j:
      enable: true                 # 启用 Knife4j
      setting:
        language: zh-CN            # 中文界面
        enable-swagger-models: true # 显示模型(Model)
        enable-document-manage: true # 启用文档管理
    

    配置了这个就别配置springdoc了,knife4j完全兼容的

  3. 编写网页数据内容以及分组

    这里的分组,元数据编写是和Springdoc完全一致的

    @Configuration
    public class OpenApiConfig {
    
        @Bean
        public OpenAPI customOpenAPI() {
            return new OpenAPI()
                    .info(new Info()
                            .title("测试 API")//标题
                            .version("1.0.0")//api的版本
                            .description("测试接口文档")//描述信息
                            .contact(new Contact()
                                    .name("技术支持")//作者
                                    .email("support@example.com"))
                            .license(new License()
                                    .name("Apache 2.0")//许可证信息
                                    .url("https://www.apache.org/licenses/LICENSE-2.0")));
        }
    
    
        // 用户接口分组
        @Bean
        public GroupedOpenApi userApi() {
            return GroupedOpenApi.builder()
                    .group("api1分组")
                    .pathsToMatch("/api1/**")
                    .build();
        }
    
        // 管理接口分组
        @Bean
        public GroupedOpenApi adminApi() {
            return GroupedOpenApi.builder()
                    .group("api2分组")
                    .pathsToMatch("/api2/**")
                    .build();
        }
    
    }
    
  4. 访问地址:http://localhost:8080/doc.html