一:前言

何为 Swagger ? 简单来说,Swagger 就是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计、构建、记录以及使用 Rest API。

为何要用 Swagger ?前后端分离的情况下,一份 Rest API 文档将会极大地提高我们的工作效率。前端小伙伴只需要对照着 Rest API 文档就可以搞清楚一个接口需要的参数以及返回值。通过 Swagger 我们只需要少量注解即可生成一份自带 UI 界面的 Rest API 文档,不需要我们后端手动编写。并且,通过 UI 界面,我们还可以直接对相应的 API 进行调试,省去了准备复杂的调用参数的过程。

这篇文章的主要内容:使用 knife4j 增强 Swagger

1:Swagger发展史

Swagger它最初由Tony Tam在2011年创建,并在之后被SmartBear Software公司收购。在过去几年中,Swagger经历了许多重大的更新和变化,
其发展史大概可以分为以下几个阶段:
①:Swagger 1.x 阶段(2011-2014年)
Swagger最初是一个简单的API文档生成工具,通过对JAX-RS和Jersey注解的支持自动生成API文档,使得API文档的维护变得更加容易。
在这个阶段,Swagger还没有完全成熟,只能支持基本的API描述和文档生成。
②:Swagger 2.x 阶段(2014-2017年)
在Swagger 2.x阶段,Swagger发生了重大变化。它不再仅仅是一个文档生成工具,而是一个完整的API开发和管理平台。Swagger 2.x加
入了强大的注解支持,可以描述API的细节信息,如请求参数、返回类型等,以及定义RESTful API的元数据,如API描述、标签等。
此外,Swagger 2.x还引入了OpenAPI规范,在API定义方面有了更严格的标准和规则。
③:OpenAPI 阶段(2017-至今)(也被称为Swagger 3.x)
    在2017年,Swagger 2.x的规范成为了Linux基金会旗下的OpenAPI规范。这标志着Swagger从一款工具演变成为了一个开放且标准的API
    定义框架。OpenAPI规范不仅继承了Swagger 2.x的特性,还提供了更加全面和严格的API定义规范,并且扩展了对非RESTful API的支持
    随着OpenAPI规范的普及,越来越多的API开发者开始使用Swagger/OpenAPI来开发、测试和文档化他们的RESTful API。
    所以,随着Linux基金会旗下的OpenAPI收购了Swagger2.x后对其进行了更严格的规范,又进行了各种优化,
    所以我们也可以称OpenAPI是一个全新的Swagger3.x,因为OpenAPI对其作了更多的优化和规范

除了上述几个主要阶段之外,还有一些其他重要的事件和版本,如Swagger UI、Swagger Codegen、SwaggerHub等等。
这些工具和服务进一步扩展了Swagger的功能,使其成为了一个更加完整、强大和易于使用的API定义和管理平台。

2:Swagger其它介绍

 其实OpenAPI规范(也称为 Swagger 3.x 规范)是一种用于描述RESTful API的标准化格式,它定义了如何描述API的基本信息、结构、参数、响应等方面的规范。OpenAPI规范以机器可读的方式定义了RESTful API的结构和特征,支持自动生成文档、客户端与服务端代码、Mock Server和测试工具等。

  OpenAPI规范最初由开发Swagger的团队在2010年推出,从Swagger 2.0开始,Swagger规范被正式更名为OpenAPI规范,并得到了许多社区的支持和贡献。OpenAPI规范采用JSON或YAML格式编写,并支持多种数据类型,可以描述API的基本信息、路径、HTTP方法、参数、响应等各种细节。通过遵循OpenAPI规范,开发者可以快速定义和构建RESTful API,并且可以生成相应的文档和代码来帮助他们更快地开发与测试API。同时,OpenAPI规范还可以促进不同系统之间的交互和集成,因为根据规范定义的API可以被多个客户端程序和服务端程序所理解和使用。

  OpenAPI阶段的Swagger也被称为Swagger 3.0。在Swagger 2.0后,Swagger规范正式更名为OpenAPI规范,并且根据OpenAPI规范的版本号进行了更新。因此,Swagger 3.0对应的就是OpenAPI 3.0版本,它是Swagger在OpenAPI阶段推出的一个重要版本。与前几个版本相比,Swagger 3.0更加强调对RESTful API的支持和规范化,提供了更丰富和灵活的定义方式,并且可以用于自动生成文档、客户端代码、服务器代码和测试工具等。

3:SpringDoc工具(推荐)

SpringDoc对应坐标是springdoc-openapi-ui,它是一个集成Swagger UI和ReDoc的接口文档生成工具,在使用上与springfox-boot-starter类似,但提供了更为灵活、功能更加强大的工具。其中除了可以生成Swagger UI风格的接口文档,还提供了ReDoc的文档渲染方式,可以自动注入OpenAPI规范的JSON描述文件,支持OAuth2、JWT等认证机制,并且支持全新的OpenAPI 3.0规范
  SpringDoc是基于OpenAPI 3.0规范构建的,因此推荐在Spring Boot 2.4及以上版本中使用springdoc-openapi-ui库来集成Swagger3.x。在这些版本中,springdoc-openapi-ui库已被广泛应用,并且得到了社区的大力支持和推广。而在Spring Boot 2.3及其以下版本,可以使用springfox-boot-starter库来集成Swagger2.x。
  SpringDoc是有着更加先进的技术架构和更好的扩展性,使得其逐渐取代了springfox-boot-starter工具包,成为了当前Spring Boot生态中最受欢迎的API文档工具之一。同时springdoc-openapi-ui还拥有更为完善的开发文档和社区支持,从而吸引了越来越多的开发者加入到这个项目中。因此作为一个Spring Boot开发者,如果想要快速、方便地生成符合OpenAPI 3.0规范的接口文档,建议使用springdoc-openapi-ui这个优秀的工具。

二:SpringBoot集成Open API 3.0(Swagger3.0)

1:引入Maven依赖

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

这是knife4j和springboot的集成包

2:配置SwaggerOpenApiConfig(配置类方式)

注:io.swagger.v3.oas.annotations 是Swagger注解包,而io.swagger.v3.oas.models是Swagger配置类对象方式

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("Swagger3.0 (Open API) 框架学习示例文档")   // Api接口文档标题(必填)
                        .description("我的API文档")                       // Api接口文档描述

                        // 联系人信息(contact),构建API的联系人信息,用于描述API开发者的联系信息,包括名称、URL、邮箱等
                        // name:文档的发布者名称 url:文档发布者的网站地址,一般为企业网站 email:文档发布者的电子邮箱
                        .contact(new Contact()
                                .name("名字")  // 作者名称
                                .url("http://www.baidu.com") // 介绍作者的URL地址
                                .email("email") )   // 作者邮箱

                        .version("v1")           // Api接口版本

                        // 授权许可信息(license),用于描述API的授权许可信息,包括名称、URL等;
                        // 假设当前的授权信息为Apache 2.0的开源标准
                        .license(new License()
                                .name("Apache 2.0")   // 授权名称
                                .url("http://springdoc.org")// 授权信息
                                .identifier("Apache-2.0")      // 标识授权许可
                        ))
                .externalDocs(new ExternalDocumentation()   //外部文档
                        .description("外部文档")
                        .url("https://www.baidu.com"));
    }

}

3:配置SwaggerOpenApiConfig(注解方式)

上面我们使用了Java代码创建Bean的方式,其实这种写起来感觉还行,但是在使用了注解方式是很舒服的,下面就简单说明:

定义Swagger3.0配置信息注解:@OpenAPIDefinition (具体参考 io.swagger.v3.oas.annotations)注意:这个注解全局只能配置一个,主要配置文档信息和安全配置
说明:用于描述整个API的元信息和全局属性,可以定义和描述,包括API版本、基本信息、服务器信息、安全方案等
常用属性:
①:info:用于描述 API 基本信息的对象,包括标题、版本号、描述等属性;
②:servers:用于描述 API 服务的 URL 和配置信息的数组;
③:security:用于描述 API 安全方案的数组,其中每个安全方案包含多个安全需求;
④:tags:用于描述 API 标签的数组,每个标签包含名称、描述等属性;
⑤:externalDocs:用于描述外部文档链接的对象,包含描述和 URL 两个属性。

import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
import io.swagger.v3.oas.annotations.servers.Server;
import org.springframework.boot.SpringBootConfiguration;

/**
 * @author Anhui OuYang
 * @version 1.0
 **/
@SpringBootConfiguration
@OpenAPIDefinition(
        // ## API的基本信息,包括标题、版本号、描述、联系人等
        info = @Info(
                title = "Swagger3.0 (Open API) 框架学习示例文档",       // Api接口文档标题(必填)
                description = "学习Swagger框架而用来定义测试的文档",      // Api接口文档描述
                version = "1.2.1",                                   // Api接口版本
                termsOfService = "https://example.com/",             // Api接口的服务条款地址
                contact = @Contact(
                        name = "蚂蚁小哥",                            // 作者名称
                        email = "xiaofeng@qq.com",                  // 作者邮箱
                        url = "https://www.cnblogs.com/antLaddie/"  // 介绍作者的URL地址
                ),
                license = @License(                                                // 设置联系人信息
                        name = "Apache 2.0",                                       // 授权名称
                        url = "https://www.apache.org/licenses/LICENSE-2.0.html"   // 授权信息
                )
        ),
        // ## 表示服务器地址或者URL模板列表,多个服务地址随时切换(只不过是有多台IP有当前的服务API)
        servers = {
                @Server(url = "http://192.168.2.235/demo/", description = "本地服务器一服务"),
                @Server(url = "http://192.168.2.236/demo/", description = "本地服务器二服务"),
        },
        externalDocs = @ExternalDocumentation(description = "更多内容请查看该链接", url = "xxx"))
public class SwaggerOpenApiConfig {
}

4:配置API接口信息(注解,重要)

// 响应对象模型定义
@Data
@AllArgsConstructor
@Schema(description = "响应返回数据对象")
public class AjaxResult {

    @Schema(
            title = "code",
            description = "响应码",
            format = "int32",
            requiredMode = Schema.RequiredMode.REQUIRED
    )
    private Integer code;

    @Schema(
            title = "msg",
            description = "响应信息",
            accessMode = Schema.AccessMode.READ_ONLY,
            example = "成功或失败",
            requiredMode = Schema.RequiredMode.REQUIRED
    )
    private String msg;

    @Schema(title = "data", description = "响应数据", accessMode = Schema.AccessMode.READ_ONLY)
    private Object data;
}
// 模型定义示例:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
@Schema(title = "User模型", description = "User属性定义的bean")
public class User {

    @Schema(name = "用户ID", description = "用户ID属性", format = "int64", example = "1")
    private int id;
    @Schema(name = "用户名称", description = "用户名称属性")
    private String name;
    @Schema(name = "用户年龄", description = "用户年龄属性")
    private int age;
    @Schema(name = "用户money", description = "用户money属性")
    private double money;

}
// 接口定义
@RestController
@RequestMapping("/user")
@Tag(
        name = "UserControllerAPI",
        description = "用户控制器接口",
        externalDocs = @ExternalDocumentation(
                description = "这是一个接口文档介绍",
                url = "https://www.baidu.com"))
public class UserController {
    @Autowired
    private UserService userService;

    @Operation(
            summary = "根据Id查询用户信息",
            description = "根据Id查询用户信息,并返回响应结果信息",
            parameters = {
                    @Parameter(name = "id", description = "学生ID", required = true, example = "1")
            },
            responses = {
                    @ApiResponse(
                            responseCode = "200",
                            description = "响应成功",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            title = "AjaxResul和User组合模型",
                                            description = "返回实体,AjaxResult内data为User模型",
                                            anyOf = {AjaxResult.class, User.class})
                            )
                    ),
                    @ApiResponse(
                            responseCode = "500",
                            description = "响应失败",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            title = "AjaxResul模型",
                                            description = "返回实体,AjaxResult内data为空",
                                            implementation = AjaxResult.class)
                            )
                    )
            }
    )
    @ResponseBody
    @GetMapping("/queryById")
    public User testUserById(@RequestParam("id") Integer id) {
        return userService.selectUserById(id);
    }
}

配置文档标题及归类,就是在Controller上配置。

注解:@Tag 可以用于对接口进行分类和归类,便于开发人员组织和管理 API 文档
    具体属性:
        ①:name:表示标签的名称,必填属性,也得注意多个Controller上的name不要写一样的,这样就会把它们归类在一起。
        ②:description:表示标签的描述信息,非必填属性。
        ③:externalDocs:用于指定URL地址文档信息来追加描述接口的信息。非必填属性。

配置文档下的每一个接口信息,就是Controller里的每一个RequestMapping

注解:@Operation用于对API操作(即方法)进行描述和标记。就是我们熟知的Controller下的一个个请求的方法上。
    具体可以参考 io.swagger.v3.oas.annotations。
    具体属性:
        ①:summary:用于简要描述API操作的概要。
        ②:description:用于详细描述API操作的描述信息。
        ③:parameters:用于指定API操作的参数列表,包括路径参数、请求参数、请求头部等。可以使用@Parameter注解进一步定义参数。
        ④:operationId:用于指定API操作的唯一标识符,可以用于生成客户端代码或文档等。
            说明:第三方工具使用operationId来唯一标识此操作。(具体我也没用过)
        ⑤:requestBody:用于定义API操作的请求体,可以使用@RequestBody注解进一步定义请求体。
            说明:这里的@RequestBody注解是@io.swagger.v3.oas.annotations.parameters.RequestBody包里的
        ⑥:responses:用于定义 API 操作的响应列表,包括成功响应和错误响应。可以使用@ApiResponse注解进一步定义响应。
        ⑦:security:用于对API操作进行安全控制,可以使用@SecurityRequirement注解进一步定义安全需求。(后面说)
        ⑧:deprecated:表示该API操作已经过时或不推荐使用。

配置请求接口参数信息

注解:@Parameter用于描述HTTP请求的参数信息,它是一个Parameter[]类型的数组,每个元素表示一个请求参数;
    具体参考:io.swagger.v3.oas.annotations;它是一个注解,和Parameter类一样,只不过一个是注解一个是类的方式
        ①:name:参数名称。
        ②:in:参数位置,可以是 query、header、path、cookie 等。
        ③:description:参数描述。
        ④:required:参数是否必须,默认为 false。
        ⑤:deprecated:参数是否已过时,默认为 false。
        ⑥:allowEmptyValue:是否允许空值,默认为false。
        ⑦:style:参数的序列化风格,可以是 "matrix"、"label"、"form"、"simple"、
            "spaceDelimited"、"pipeDelimited"、"deepObject";
        ⑧:explode:当参数值是对象或数组时,是否将其展开成多个参数,默认为 false。
        ⑨:schema:参数类型和格式的定义,通常使用@Schema注解。(下面介绍)
        ⑩:example:参数值的示例;

 配置具体的实体模型信息

注解:@Schema 是用于描述数据模型的基本信息和属性,具体可以参考“io.swagger.v3.oas.annotations.media”
具体属性:
①:description:用于描述该类或属性的作用。
②:name:指定属性名。该属性只对属性有效,对类无效。
③:title:用于显示在生成的文档中的标题。
④:requiredMode:用于指定该属性是否必填项。枚举Schema.RequiredMode内可选值如下:
默认AUTO:可有可无;REQUIRED:必须存在此字段(会加红色*);NOT_REQUIRED:不需要存在此字段
⑤:accessMode:用于指定该属性的访问方式。
包括AccessMode.READ_ONLY(只读)、AccessMode.WRITE_ONLY(只写)、AccessMode.READ_WRITE(读写)
⑥:format:用于指定该属性的数据格式。例如:日期格式、时间格式、数字格式。
⑦:example:为当前的属性创建一个示例的值,后期测试可以使用此值。
⑧:deprecated:用于指定该属性是否为已过时的属性,默认为false。
⑨:defaultValue:用于指定该属性的默认值。
⑩:implementation:用于显示为该类或属性引入具体的实体路径,这代表当前指定的类或者属性将参考引入的实体。
就是说有个实体类,这个类里面有个teacher属性,这时里面的teacher属性可以指定具体的实体类

@Schema注解:提供了四个属性来描述复杂类型,分别是allOf、anyOf、oneOf和not。
这四个属性可以用于组合不同的JSON Schema以描述一个复杂类型,具体如下:
①:allOf: 表示当前schema是多个其它schema的并集。
例如,如果一个Java类型同时实现了两个接口,那么可以使用allOf来表示这个Java类型继承了这两个接口的所有属性和方法。
②:anyOf: 表示当前schema可以匹配其中任意一个schema,其本身也是一个组合体,可以嵌套使用。
例如,一个返回类型可能是多个Java类型中的任意一个,可以使用anyOf来描述这种情况。
③:oneOf: 表示当前schema只能匹配其中一个schema,其本身也是一个组合体,可以嵌套使用。
例如,一个Java类型只能是多个子类型中的任意一个,可以使用oneOf来描述这种情况。
④:not: 表示当前Schema不能匹配某个schema。
例如,一个Java类型不能是某个子类型,可以使用not来描述这种情况。

三:权限认证方式

其实我们的接口都是有权限校验方式的,每个接口在请求时都是包含校验,如我们常见的JWT校验,我们访问每个接口都需要携带Token信息,下面我就简单说说校验认证的方式描述。

注解权限设置:@SecurityScheme (具体参考io.swagger.v3.oas.annotations.security)
说明:用于定义API的安全方案。通过使用@SecurityScheme注解,我们可以为API定义多种安全方案,并指定每种方案的相关属性,
例如认证类型、授权URL、令牌URL、作用域等。
常用属性:
①:name:
安全方案的名称;
②:type:
认证类型,具体包含如下:SecuritySchemeType.API_KEY(API密钥)、SecuritySchemeType.HTTP(HTTP认证)、
SecuritySchemeType.OAUTH2(OAuth2.0 认证)等;
③:description:
安全方案的描述信息;
④:in:
仅在使用API密钥认证时适用,表示API密钥的位置,包括如下:
ApiKeyLocation.HEADER(HTTP 头部)、ApiKeyLocation.COOKIE(Cookie)等
⑤:scheme:
仅在使用HTTP认证时适用,表示认证方案,例如HTTP Authentication Scheme.Basic(Basic 认证);
防止客户端需要在请求头部中添加一个包含用户名和密码的 Base64 编码字符串,并以 “Basic ” 开头,如:
Authorization: Basic YWRtaW46MTIzNDU2
⑥:bearerFormat:
仅在使用 Bearer Token 认证时适用,表示 Bearer Token 的格式;
⑦:flows:
仅在使用OAuth2.0认证时适用,表示OAuth2.0的认证流程,包括@OAuthFlows.authorizationCode、
@OAuthFlows.clientCredentials、@OAuthFlows.password 和 @OAuthFlows.implicit等。
示例:(可以在我们自定义的SwaggerOpenApiConfig内设置权限认证)

@SecurityScheme(
            name = "JWT-test",                   // 认证方案名称
            type = SecuritySchemeType.HTTP,      // 认证类型,当前为http认证
            description = "这是一个认证的描述详细",  // 描述信息
            in = SecuritySchemeIn.HEADER,        // 代表在http请求头部
            scheme = "bearer",                   // 认证方案,如:Authorization: bearer token信息
            bearerFormat = "JWT")                // 表示使用 JWT 格式作为 Bearer Token 的格式

比如我添加了一个名称为”JWT-test“的验证方式,使用方式存在2种,一种是设置全部文档使用这种验证,另一种是某个接口使用此种校验方式,具体使用如下:

当前在自定义的SwaggerOpenApiConfig类上面设置了两种权限校验方式,如下:
@SecurityScheme(
        name = "JWT-test",                   // 认证方案名称
        type = SecuritySchemeType.HTTP,      // 认证类型,当前为http认证
        description = "这是一个认证的描述详细",  // 描述信息
        in = SecuritySchemeIn.HEADER,        // 代表在http请求头部
        scheme = "bearer",                   // 认证方案,如:Authorization: bearer token信息
        bearerFormat = "JWT")                // 表示使用 JWT 格式作为 Bearer Token 的格式
@SecurityScheme(
        name = "X-API-KEY",
        type = SecuritySchemeType.APIKEY,
        description = "这是一个认证的描述详细",
        in = SecuritySchemeIn.HEADER,
        scheme = "bearer")
@OpenAPIDefinition(
        security = {@SecurityRequirement(name = "JWT-test"),
                @SecurityRequirement(name = "X-API-KEY")}
)

设置全部接口描述都有指定的一种校验方式:
    在@OpenAPIDefinition注解里的security属性设置校验方式
    @OpenAPIDefinition(   
        ....
        security = @SecurityRequirement(name = "JWT-test")
    )
设置指定接口描述有指定的一种校验方式:
    在@Operation注解里的security属性设置校验方式
    @Operation(   
        ....
        security = @SecurityRequirement(name = "JWT-test")
    )

权限认证(这里我配置两个在Swagger配置类上)

四:启动项目,查看文档

knife4j 访问地址:http://localhost:8080/doc.html

swagger访问地址:http://localhost:8080/swagger-ui.html

分类: SpringBoot

0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注