初级-使用springdoc对SpringBoot项目支持Swagger-UI

568 阅读14分钟

0-编辑历史

2023-10-13 10:27 , springdoc-openapi v2.2.0 , 这篇文章是我学习记录的汇总,仅供参考

宜朝西编程 可以触摸的痛苦就是肚子都饿扁了,一摸还是有一坨肉

1-参考资料

chatgpt

springdoc: springdoc.org/

OpenAPI Specification: swagger.io/docs/specif…

项目基础: juejin.cn/post/728896…

2-RESTful APIs

REST(Representational State Transfer)是一种设计网络应用程序的架构风格。RESTful APIs(RESTful Application Programming Interfaces)是基于REST原则的API设计,用于在客户端和服务器之间进行通信。

RESTful APIs 使用标准的HTTP方法(如GET、POST、PUT、DELETE)来执行对资源的操作,以及使用URL(统一资源定位符)来标识和定位资源。它通过提供一组简单而统一的规则,使得不同系统之间可以通过HTTP协议进行数据交互。

以下是 REST APIs 的一些核心特点:

资源(Resources):RESTful APIs 将应用程序的数据和功能抽象为资源,并使用唯一的URL(统一资源定位符)来标识每个资源。例如,一个博客文章可以表示为 /articles/{id} 的 URL。

HTTP 方法(HTTP Methods):RESTful APIs 使用标准的 HTTP 方法来定义对资源的操作。常见的HTTP方法包括 GET(获取资源)、POST(创建资源)、PUT(更新资源)和 DELETE(删除资源)。

表示层(Representation):RESTful APIs 通过表示层来传递和处理资源的状态。在传输过程中,可以使用各种表示格式,如 JSON、XML、HTML等。客户端和服务器之间的数据交互通常使用 JSON 格式。

无状态(Stateless):RESTful APIs 是无状态的,即在每个请求之间不保留任何会话或状态信息。每个请求都应该包含足够的信息来完全描述所需的操作。

通过使用 RESTful APIs,可以提供一种灵活、可扩展且易于理解的方式进行系统间通信。它促进了解耦和模块化的架构设计,并提供了统一的接口来访问和操作资源。因此,RESTful APIs 在现代的 Web 开发中被广泛应用,成为构建可靠和可伸缩的应用程序的常用方法。

3-OpenAPI Specification

OpenAPI Specification (formerly Swagger Specification) is an API description format for REST APIs.

OpenAPI 规范(OpenAPI Specification)是一种用于描述和定义 RESTful Web Services API 的规范。它提供了一套结构化的规则和约定,以规范和标准化 API 的设计、文档和交互方式。

OpenAPI 规范使用 JSONYAML 格式编写,定义了 API 的各个方面,包括资源、操作、参数、响应、认证、版本管理等等。它提供了一种统一的标准,使得开发者和工具可以根据规范自动生成文档、进行代码生成、执行自动化测试等操作。

通过 OpenAPI 规范,可以实现以下功能:

  1. 设计API:通过定义资源、操作、参数和响应等,可以清晰地设计和建模 API 的结构和行为。

  2. 自动生成文档:基于 OpenAPI 规范,可以自动生成具有交互式界面的 API 文档,其中包括了 API 的详细信息、可用的操作、参数说明、示例请求和响应等。

  3. 代码生成:利用 OpenAPI 规范,可以生成客户端和服务器端的代码,以便快速启动开发,并确保接口定义的一致性。

  4. 自动化测试:使用 OpenAPI 规范,可以自动生成 API 的测试用例,从而简化测试工作并提高测试覆盖率。

OpenAPI 规范不仅能够帮助开发者更好地设计和理解 API,还能提供一种通用的方式来描述和交互 API。它的出现使得 API 的设计和管理更加标准化和规范化,从而提高开发效率、降低沟通成本,并促进了 API 生态系统的发展。

4-Swagger

Swagger 是一组开源工具和规范,用于设计、构建、文档化和使用 RESTful Web Services API。它提供了一种简单且强大的方式来描述和定义 API,使得开发者能够更轻松地创建和管理 API。

主要组件和功能包括:

Swagger Editor:一个可视化的编辑器,用于编写和编辑符合 OpenAPI 规范的 API 描述文档。可以直接在 Swagger Editor 中编写 OpenAPI 规范的 YAML 或 JSON 文件,并实时查看 API 文档的预览效果。

Swagger UI:一个动态的交互式文档生成工具,用于自动生成漂亮的、可浏览的 API 文档。通过 Swagger UI,开发者可以以用户友好的方式浏览 API 的资源、操作、参数等信息,并通过界面进行 API 的测试和调试。

Swagger Codegen:一个代码生成器,根据 API 描述文档自动生成客户端和服务器端的代码。开发者可以选择使用不同的编程语言和框架,生成符合规范的代码,从而快速集成和使用 API。

SwaggerHub:一个云端的 API 设计和文档平台,用于协作开发和管理 API。开发者可以在 SwaggerHub 上创建和托管 API 描述文档,并与团队成员共享和协作编辑。同时,SwaggerHub 还提供了集成工具和其他高级功能,以简化 API 的设计、测试和部署过程。

总体而言,Swagger 提供了一套完整的工具链,帮助开发者更好地设计、构建和文档化 RESTful Web Services API。它的目标是提供一种统一的方式来描述和使用 API,从而促进 API 的可视化、可测试性和可交互性,并加速 API 的开发和集成过程。

5-springdoc

springdoc 是一个用于生成 OpenAPI(以前称为 Swagger)规范的库,专门针对基于 Spring 框架构建的 RESTful Web Services API。它提供了一种方便且易于集成的方式,将 API 的注解和配置转换为符合 OpenAPI 规范的文档。

springdoc 主要功能和特点包括:

自动生成 API 文档:基于注解驱动的方式,springdoc 可以自动扫描 Spring MVC 控制器和相关的注解,并根据这些注解生成对应的 API 文档。开发者只需要在代码中添加相应的注解,就可以自动生成具有详细描述、参数说明、响应信息等的 API 文档。

支持 OpenAPI 规范:springdoc 严格遵循 OpenAPI 规范(原 Swagger 规范),并支持最新的 OpenAPI 3.x 版本。它能够生成符合规范的 API 描述文件,用于定义 API 的结构、操作、参数、响应等信息。

集成 Spring Boot:springdoc 是为 Spring Boot 框架设计的,可以与 Spring Boot 应用程序无缝集成。通过简单的配置,开发者可以轻松地将 springdoc 引入到现有的 Spring Boot 项目中,并自动生成 API 文档。

与 Swagger UI 集成:springdoc 提供了与 Swagger UI 的集成,可以直接在浏览器中查看和测试生成的 API 文档。通过配置,开发者可以轻松地将 Swagger UI 集成到应用程序中,以实现可交互的 API 文档展示和测试。

总之,springdoc 是一个方便的库,可以帮助开发者快速生成符合 OpenAPI 规范的 API 文档。它与 Spring Boot 紧密集成,并支持最新的 OpenAPI 3.x 版本,为基于 Spring 框架的 API 提供了简单、可靠的文档生成解决方案。

springdoc-openapi java library supports OpenAPI 3Swagger-ui

6-从 Swagger 1.0 到 Swagger 2.0 到最新的 OpenAPI 3.0

OpenAPI Specification(之前被称为 Swagger Specification)是一种用于描述 REST APIs 的规范,提供了一种标准化的方法来定义和文档化 API。

下面是 OpenAPI Specification 的发展历程:

Swagger 1.0:Swagger 最初由 Reverb Technologies 创建,在2011年发布了第一个版本(Swagger 1.0)。Swagger 1.0 采用了 JSON 或 YAML 格式来定义 API,包含了一些基本的元素,例如 API 的路径、HTTP 方法、参数等。

Swagger 2.0:在 Swagger 1.0 的基础上,Swagger 2.0 将规范扩展为了一个更为全面的描述语言,支持更多的 API 元素。Swagger 2.0 发布于2014年,包括了更完整的数据类型、请求体及响应的定义方式、OAuth2 支持等改进,同时 Swagger 2.0 也开始使用 "OpenAPI Specification" 这个名称。

OpenAPI 3.0:OpenAPI 3.0 发布于2017年,是对 Swagger 2.0 的重大更新。OpenAPI 3.0 在 Swagger 2.0 的基础上,重新设计了规范,增加了许多新功能和改进。例如,增加了对不同编程语言的所需的 OpenAPI 代码生成支持、新增了 Webhooks 以支持事件驱动的 API 和纯 JSON 的描述模型等。

总之,OpenAPI Specification 的发展历程经历了从 Swagger 1.0Swagger 2.0 到最新的 OpenAPI 3.0 的变化,规范越来越完善和健全,提供了更多的优秀特性和选择。现在,OpenAPI Specification 已成为 REST API 设计和开发的行业标准之一,被广泛使用和支持。

7-添加springdoc-openapi依赖

For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed)

maven:

<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.2.0</version>
</dependency>

gradle:

// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.2.0'

This will automatically deploy swagger-ui to a spring-boot application:

  • Documentation will be available in HTML format, using the official swagger-ui jars

  • The Swagger UI page will then be available at http://server:port/context-path/swagger-ui.html and the OpenAPI description will be available at the following url for json format: http://server:port/context-path/v3/api-docs

    • server: The server name or IP

    • port: The server port

    • context-path: The context path of the application

  • Documentation can be available in yaml format as well, on the following path : /v3/api-docs.yaml

8-custom path

For custom path of the swagger documentation in HTML format, add a custom springdoc property, in your spring-boot configuration file: .

# swagger-ui custom path
springdoc.swagger-ui.path=/swagger-ui.html
springdoc:
  swagger-ui:
    path: /swagger-ui/index.html

9-Springdoc-openapi Properties

9-1-springdoc-openapi core properties

2023-10-13 11:33,项目中常用的 springdoc-openapi 属性

Parameter name: springdoc.api-docs.path
Default Value: /v3/api-docs
Description: String, For custom path of the OpenAPI documentation in Json format.
Parameter name: springdoc.api-docs.enabled
Default Value: true
Description: Boolean. To disable the springdoc-openapi endpoint (/v3/api-docs by default).
Parameter name: springdoc.packages-to-scan
Default Value: *
Description: List of Strings.The list of packages to scan (comma separated)
Parameter name: springdoc.cache.disabled
Default Value: false
Description: Boolean. To disable the springdoc-openapi cache of the calculated OpenAPI.

9-2-swagger-ui properties

Parameter name: springdoc.swagger-ui.path
Default Value: /swagger-ui.html
Description: String, For custom path of the swagger-ui HTML documentation.
Parameter name: springdoc.swagger-ui.enabled
Default Value: true
Description: Boolean. To disable the swagger-ui endpoint (/swagger-ui.html by default).
Parameter name: springdoc.swagger-ui.tagsSorter
Default Value: 
Description:  Function=(a ⇒ a). Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function see Array.prototype.sort() to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger UI.

9-3-spring-boot configuration file

2023-10-13 11:39,给大家看一下我的示例, 如上所述 springdoc.api-docs.path 的默认值就是 /v3/api-docs

springdoc:
  api-docs:
    enabled: true
    path: /v3/api-docs
    version: openapi_3_0
  swagger-ui:
    path: /swagger-ui/index.html
    tagsSorter: alpha
    use-root-path: true
  cache:
    disabled: true

10-启动类入口修改

对启动类作如下修改

package com.example.lkcoffee;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author 
 */
@SpringBootApplication
public class LkcoffeeApplication {

    private static final Logger logger = LoggerFactory.getLogger(LkcoffeeApplication.class);

    /**
     * Swagger地址:http://localhost:8080/swagger-ui/index.html#/
     * 参考资料:https://dzone.com/articles/openapi-3-documentation-with-spring-boot
     * @param args args
     */
    public static void main(String[] args) throws UnknownHostException {

        ApplicationContext applicationContext =  SpringApplication.run(LkcoffeeApplication.class, args);
        Environment environment = applicationContext.getEnvironment();

        logger.info("\n---------------------------------------------lkcoffee-----------------------------------------------------------------------\n" +
                        "应用 '{}' 运行成功! \n" +
                        "Swagger-UI-Interface 访问连接: http://{}:{}{}{} \n" +
                        "API-Docs 访问连接: http://{}:{}{}{} \n" +
                        "--------------------------------------------------------------------------------------------------------------------",

                environment.getProperty("spring.application.name"),

                InetAddress.getLocalHost().getHostAddress(),
                environment.getProperty("server.port", "8080"),
                environment.getProperty("server.servlet.context-path", ""),
                environment.getProperty("springdoc.swagger-ui.path", "/swagger-ui/index.html"),

                InetAddress.getLocalHost().getHostAddress(),
                environment.getProperty("server.port", "8080"),
                environment.getProperty("server.servlet.context-path", ""),
                environment.getProperty("springdoc.api-docs.path", "/v3/api-docs")

        );
    }
}

11-代码修改

11-1-替换注解

根据 Migrating from SpringFox 章节

Swagger 3 引入了一些新的注解,并对原有的注解进行了调整。下面是注解的使用场景发生变化的详细说明:

  1. @Api@Tag:Swagger 3 中将 @Api 注解替换为 @Tag 注解,用于对 API 接口进行分组和标记

  2. @ApiIgnore@Parameter(hidden = true)@Operation(hidden = true)@Hidden:Swagger 3 中取消了 @ApiIgnore 注解,取而代之的是通过其他注解来实现隐藏某个参数或操作。可以使用 @Parameter(hidden = true)@Operation(hidden = true)@Hidden 注解来实现隐藏功能。

  3. @ApiImplicitParam@Parameter:Swagger 3 中将 @ApiImplicitParam 注解替换为 @Parameter 注解,用于描述接口参数

  4. @ApiImplicitParams@Parameters:Swagger 3 中将 @ApiImplicitParams 注解替换为 @Parameters 注解,用于对多个参数进行描述。

  5. @ApiModel@Schema:Swagger 3 中将 @ApiModel 注解替换为 @Schema 注解,用于描述数据模型。

  6. @ApiModelProperty(hidden = true)@Schema(accessMode = READ_ONLY):Swagger 3 中取消了 @ApiModelProperty(hidden = true) 注解,取而代之的是使用 @Schema(accessMode = READ_ONLY) 注解实现隐藏某个属性。

  7. @ApiModelProperty@Schema:Swagger 3 中将 @ApiModelProperty 注解替换为 @Schema 注解,用于描述属性

  8. @ApiOperation(value = "foo", notes = "bar")@Operation(summary = "foo", description = "bar"):Swagger 3 中将 @ApiOperation 注解替换为 @Operation 注解,用于对接口进行详细描述

  9. @ApiParam@Parameter:Swagger 3 中将 @ApiParam 注解替换为 @Parameter 注解,用于描述接口参数

  10. @ApiResponse(code = 404, message = "foo")@ApiResponse(responseCode = "404", description = "foo"):Swagger 3 中将 @ApiResponse 注解中的 code 属性替换为 responseCode 属性,用于描述响应结果

11-2-修改后的控制器层代码

package com.example.lkcoffee.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.lkcoffee.persistence.entity.Coffee;
import com.example.lkcoffee.search.CoffeeSearchCriteria;
import com.example.lkcoffee.service.CoffeeService;
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.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * The type Coffee controller.
 *
 * @author yang.jianming3
 * @version 1.0
 * @since 2023 /10/11 10:09
 */
@Tag(name = "lkCoffee API")
@RestController
@RequestMapping("/coffee")
public class CoffeeController {

    @Autowired
    private CoffeeService coffeeService;

    /**
     * Gets coffee page.
     *
     * @param rating     the rating
     * @param pageNumber the page number
     * @param pageSize   the page size
     * @return the user page
     */
    @Operation(summary = "按评分获取咖啡分页列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取咖啡分页列表"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/page")
    public ResponseEntity<IPage<Coffee>> getCoffeePage(
            @Parameter(description = "咖啡评分") @RequestParam float rating,
            @Parameter(description = "页码,默认为1") @RequestParam(defaultValue = "1") Long pageNumber,
            @Parameter(description = "每页记录数,默认为10") @RequestParam(defaultValue = "10") Long pageSize
    ) {
        CoffeeSearchCriteria coffeeSearchCriteria = new CoffeeSearchCriteria();
        coffeeSearchCriteria.setRating(rating);
        coffeeSearchCriteria.setCurrentPage(pageNumber);
        coffeeSearchCriteria.setPageSize(pageSize);
        IPage<Coffee> coffeeIPage = coffeeService.getCofeePage(coffeeSearchCriteria);
        return ResponseEntity.ok(coffeeIPage);
    }

    /**
     * Gets coffee list.
     *
     * @return the coffee list
     */
    @Operation(summary = "获取咖啡列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取咖啡列表"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/list")
    public ResponseEntity<List<Coffee>> getCoffeeList() {
        List<Coffee> coffeeList = coffeeService.list();
        return ResponseEntity.ok(coffeeList);
    }

    /**
     * Gets coffee by id.
     *
     * @param id the id
     * @return the coffee by id
     */
    @Operation(summary = "根据 ID 获取咖啡")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取咖啡"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/{id}")
    public ResponseEntity<Coffee> getCoffeeById(
            @Parameter(description = "咖啡 ID") @PathVariable Integer id) {
        Coffee coffee = coffeeService.getById(id);
        return ResponseEntity.ok(coffee);
    }

    /**
     * Save coffee response entity.
     *
     * @param coffee the coffee
     * @return the response entity
     */
    @Operation(summary = "保存咖啡")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "成功保存咖啡"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/save")
    public ResponseEntity<Void> saveCoffee(@RequestBody Coffee coffee) {
        coffeeService.save(coffee);
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }

    /**
     * Update coffee by id response entity.
     *
     * @param coffee the coffee
     * @return the response entity
     */
    @Operation(summary = "更新咖啡")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "成功更新咖啡"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PutMapping("/update")
    public ResponseEntity<Void> updateCoffeeById(@RequestBody Coffee coffee) {
        coffeeService.updateById(coffee);
        return ResponseEntity.noContent().build();
    }

    /**
     * Delete coffee by id response entity.
     *
     * @param id the id
     * @return the response entity
     */
    @Operation(summary = "根据 ID 删除咖啡")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "成功删除咖啡"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteCoffeeById(
            @Parameter(description = "咖啡 ID") @PathVariable Integer id
    ) {
        coffeeService.removeById(id);
        return ResponseEntity.noContent().build();
    }
}

11-3-实体类修改

可以在实体类加上 @Schema(description = "coffee model") 注解,描述数据模型

12-添加 OpenAPI Bean

bean of OpenAPI type.

Springdoc 中,OpenAPI 类是一个代表 OpenAPI 规范的对象模型,用于描述和定义 API 文档。

OpenAPI 对象包含了 API 的基本信息,如标题、描述、版本号等,还包括了 API 的路径、操作、参数、响应等详细信息。它可以用于生成符合 OpenAPI 规范的 API 文档,这些文档可以用于 API 的文档化、交流和测试。

OpenAPI 类有如下字段

    private String title = null;
    private String description = null;
    private String termsOfService = null;
    private Contact contact = null;
    private License license = null;
    private String version = null;
    private java.util.Map<String, Object> extensions = null;

Springdoc 中,您可以创建一个 OpenAPI 对象的实例,并通过配置该实例来自定义 API 文档。您可以添加全局参数、安全定义、服务器信息等到 OpenAPI 对象中,以满足您的特定需求。

OpenAPI 对象可以与 Spring Boot 应用程序集成,以便自动化生成 OpenAPI 文档。它与 Springdoc 提供的其他组件(如 DocketGroupedOpenApi)一起使用,以便更好地管理和生成 API 文档。

package com.example.lkcoffee.config;

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
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;

/**
 * The type Swagger config.
 *
 * @author yang.jianming3
 * @version 1.0
 * @since 2023 /10/13 13:14
 */
@Configuration
public class SwaggerConfig {
    /**
     * Lk coffee open api.
     *
     * @return the open api
     */
    @Bean
    public OpenAPI lkCoffeeOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("lkCoffee API")
                        .description("lkCoffee application")
                        .version("v0.0.1")
                        .license(new License().name("Apache 2.0").url("http://springdoc.org")))
                .externalDocs(new ExternalDocumentation()
                        .description("lkCoffee Wiki Documentation")
                        .url("http://springdoc.org"));
    }
}

13-springfox vs springdoc

OAS 3 was released in July 2017, and there was no release of springfox to support OAS 3.

springfox covers for the moment only swagger 2 integration with Spring Boot. The latest release date is June 2018. So, in terms of maintenance there is a big lack of support lately.

The biggest difference with springfox, is that springdoc integrate new features not covered by springfox:

The integration between Spring Boot and OpenAPI 3 standard.

springdoc rely on swagger-annotations and swagger-ui only official libraries.

14-Summary

这篇文章主要是介绍 RESTful APIsOpenAPI SpecificationSwaggerSwagger-UISpringdocSpringfox 这些概念

RESTful APIs 是一种设计原则,OpenAPI SpecificationSwagger 是用于描述和文档化这种 API 设计的标准和工具,而 SpringdocSpringfox 是用于在 Spring Boot 应用程序中生成符合 OpenAPI Specification 标准的 API 文档的库。最后,Swagger-UI 则是一个用于直观展示 API 文档并在浏览器中调试 API 的 Web 界面。

并介绍如何在一个 Spring Boot 项目中快速集成 springdoc 提供对 Swagger-UI 的支持。