• 集成 Spring Doc 接口文档和 knife4j-SpringBoot 2.7.2 实战基础


    优雅哥 SpringBoot 2.7.2 实战基础 - 04 -集成 Spring Doc 接口文档和 knife4j

    前面已经集成 MyBatis Plus、Druid 数据源,开发了 5 个接口。在测试这 5 个接口时使用了 HTTP Client 或 PostMan,无论是啥都比较麻烦:得自己写请求地址 URL、请求参数等,于是多年前就出现了 Swagger 这个玩意。Swagger 可以自动生成接口文档,还能很方便的测试各个接口。但不幸的是,MVN Repository 上面 Springfox Swagger2 的版本停止于 2020 年 7月,而写下这篇文章是 2022 年 8 月,已经两年过去没有动静了,与此同时,springdoc-openapi 悄然出现。

    spring doc open api 支持 Open API 3、Swagger-ui等,可以很方便与 Spring Boot 整合,配置和使用与 Springfox Swagger2 类似。

    1 集成 Spring Doc

    1.1 添加依赖

    springdoc-openapi 不是 Spring Framework 官方团队开发的,而是社区项目,没有包含在 spring-boot-dependencies 中。故需要先定义版本号:

    <properties>
    		....
        <springdoc-openapi-ui.version>1.6.9springdoc-openapi-ui.version>
    properties>
    

    添加依赖:

    <dependency>
        <groupId>org.springdocgroupId>
        <artifactId>springdoc-openapi-uiartifactId>
        <version>${springdoc-openapi-ui.version}version>
    dependency>
    

    该依赖里面使用了 swagger-ui,以HTML形式展示文档。

    1.2 编写配置类

    其实配置类写不写都可以,如果不写配置类,就通过注解定义文档信息就可以。创建类:com.yygnb.demo.config.SpringDocConfig

    package com.yygnb.demo.config;
    
    import io.swagger.v3.oas.models.ExternalDocumentation;
    import io.swagger.v3.oas.models.OpenAPI;
    import io.swagger.v3.oas.models.info.Info;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class SpringDocConfig {
    
        private String title = "Hero SpringBoot Demo";
        private String description = "Hero Demo for usage of Spring Boot";
        private String version = "v0.0.1";
        private String websiteName = "Hero Website";
        private String websiteUrl = "http://www.yygnb.com";
    
        @Bean
        public OpenAPI heroOpenAPI() {
            return new OpenAPI()
                    .info(new Info().title(title)
                            .description(description)
                            .version(version))
                    .externalDocs(new ExternalDocumentation().description(websiteName)
                            .url(websiteUrl));
        }
    }
    

    上面的配置定义了展示的文档的信息,与界面上对应关系如下:

    image-20220729104035602

    在配置文件中除了可以配置文档的信息,还可以配置文档分组、Authorization 等,在后面的企业级实战文章中会具体描写,将会在网关层 spring cloud gateway 中集成所有微服务的接口。

    1.3 配置yml

    在 application.yml 配置 springdoc:

    # 接口文档
    springdoc:
      packages-to-scan: com.yygnb.demo.controller
      swagger-ui:
        enabled: true
    

    这两项不配置也可以,packages-to-scan 默认为启动类所在的路径;springdoc.swagger-ui.enabled 默认为true,配置后可以在不同的环境中开启或关闭。

    1.4 添加注解

    springdoc-openapi 与 springfox-swagger2 提供的注解有很大差别:

    swagger 2 spring doc 描述
    @Api @Tag 修饰 controller 类,类的说明
    @ApiOperation @Operation 修饰 controller 中的接口方法,接口的说明
    @ApiModel @Schema 修饰实体类,该实体的说明
    @ApiModelProperty @Schema 修饰实体类的属性,实体类中属性的说明
    @ApiImplicitParams @Parameters 接口参数集合
    @ApiImplicitParam @Parameter 接口参数
    @ApiParam @Parameter 接口参数

    修改实体类 Computer,添加 springdoc-openapi 注解:

    @Schema(title = "电脑")
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Computer implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @TableId(value = "id", type = IdType.AUTO)
        private Long id;
    
        @Schema(title = "尺寸")
        private BigDecimal size;
    
        @Schema(title = "操作系统")
        private String operation;
    
        @Schema(title = "年份")
        private String year;
    }
    

    修改控制器 ComputerController,添加注解:

    @Tag(name = "电脑相关接口")
    @RequiredArgsConstructor
    @RestController
    @RequestMapping("/computer")
    public class ComputerController {
    
        private final IComputerService computerService;
    
        @Operation(summary = "根据id查询电脑")
        @GetMapping("/{id}")
        public Computer findById(
                @Parameter(name = "id", required = true, description = "电脑id") @PathVariable Long id) {
            return this.computerService.getById(id);
        }
    
        @Operation(summary = "分页查询电脑列表")
        @Parameters(value = {
                @Parameter(name = "page", description = "页面,从1开始", example = "2"),
                @Parameter(name = "size", description = "每页大小", example = "10")
        })
        @GetMapping("/find-page/{page}/{size}")
        public Page findPage(@PathVariable Integer page, @PathVariable Integer size) {
            return this.computerService.page(new Page<>(page, size));
        }
    
        @Operation(summary = "新增电脑")
        @PostMapping()
        public Computer save(@RequestBody Computer computer) {
            computer.setId(null);
            this.computerService.save(computer);
            return computer;
        }
    
        @Operation(summary = "根据id修改电脑")
        @PutMapping("/{id}")
        public Computer update(
                @Parameter(name = "id", required = true, description = "电脑id") @PathVariable Long id,
                @RequestBody Computer computer) {
            computer.setId(id);
            this.computerService.updateById(computer);
            return computer;
        }
    
        @Operation(summary = "根据id删除电脑")
        @DeleteMapping("/{id}")
        @Parameter(name = "id", required = true, description = "电脑id")
        public void delete(@PathVariable Long id) {
            this.computerService.removeById(id);
        }
    }
    

    1.5 运行测试

    启动服务,在浏览器中访问:

    http://localhost:9099/swagger-ui/index.html
    

    image-20220729110218650

    2 api-docs

    在文档标题下面有一个小链接:/v3/api-docs,点击该链接,会在新页面中显示一大坨 JSON 数据。

    image-20220729111003036

    看似很无聊的数据,却有着重大意义,swagger-ui 就是通过这些数据渲染出页面的。此外,这些JSON数据在某种程度上可以简化前端的开发及前后端网络请求的工作量。

    hero-admin-ui

    优雅哥正在开发的基于 Vue 3 + TypeScript 的开源项目 hero-admin-ui,其特色就是基于 JSON Schema 的表单和列表。通过 JSON Schema 可以快速渲染出一个列表、表单,甚至是搜索页和详情表单页。如果独立使用 hero-admin-ui,需要手动编写 JSON Schema,但如果后端接口整合了 Swagger 或 Spring Doc,上面 api-docs 返回的 JSON,就包含了 JSON Schema,二者结合可以快速实现搜索页、表单页等。目前 hero-admin-ui 已发布在 npmjs 上,也已经提交到 github上,大家可以搜索关键字 hero-admin-ui 查看。在后面的实战篇中,前端部分将会使用这个组件库实现前端页面。

    image-20220729112239715

    3 自定义配置

    在 ”1.2 编写配置类“ 一节,文档信息都是写死在代码中的,如果多个微服务都要集成 spring doc,可以把前面写的 SpringDocConfig 提取到公共模块中,通过maven 依赖引用,在 application.yml 中配置不同的变量。

    3.1 添加依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-configuration-processorartifactId>
        <optional>trueoptional>
    dependency>
    

    配置该依赖的目的是在编写 application.yml 时,自定义的属性有代码提示。它会生成配置元数据,无需自己手动编写。

    3.2 定义配置的实体类

    创建 com.yygnb.demo.config.DocInfo,将 SpringDocConfig 中写死的属性都移到这个配置实体类中:

    @Data
    @Component
    @ConfigurationProperties(prefix = "doc-info")
    public class DocInfo {
    
        private String title = "Demo Title";
        private String description = "Demo Description";
        private String version = "v0.0.1";
        private String websiteName = "Demo Website";
        private String websiteUrl = "http://www.yygnb.com";
    }
    

    注解 @ConfigurationProperties(prefix = "doc-info") 声明配置属性,在 application.yml 配置时就可以使用 doc-info。

    3.3 重构 SpringDocConfig

    在 SpringDocConfig 中引入 DocInfo,并通过构造函数进行注入:

    @RequiredArgsConstructor
    @Configuration
    public class SpringDocConfig {
    
        private final DocInfo docInfo;
    
        @Bean
        public OpenAPI springShopOpenAPI() {
            return new OpenAPI()
                    .info(new Info().title(docInfo.getTitle())
                            .description(docInfo.getDescription())
                            .version(docInfo.getVersion()))
                    .externalDocs(new ExternalDocumentation().description(docInfo.getWebsiteName())
                            .url(docInfo.getWebsiteUrl()));
        }
    }
    

    补充一个小点:注解 @RequiredArgsConstructor 是 lombok 中提供的,它等价于在类中编写了方法:

    public SpringDocConfig(DocInfo docInfo) {
        this.docInfo = docInfo;
    }
    

    构造注入时,在构造函数中写大量的属性,毫无意义。既然已经使用了 @Data 注解,为啥不用 @RequiredArgsConstructor 呢?

    3.4 使用自定义配置

    自定义配置已经完成,可以在 application.yml 中使用 DocInfo 对应的配置了:

    doc-info:
      title: SpringBoot Demo演示
      description: 学习 Spring Boot 2.7.2
    

    DocInfo 所有属性都定义了默认值,在 application.yml 可以覆盖默认值,如上面的 titledescription 属性。重启服务查看运行效果:

    image-20220729152109364

    4 集成 knife4j

    在之前 springfox-swagger 的时代,很多同学不喜欢 swagger-ui 的界面风格,会集成 knife4j 的 ui。Spring Doc 也可以集成 knife4j。

    如果要使用 knife4j ,Spring Doc 的配置中需要添加分组配置,我们这里添加一个最简单的分组配置。

    com.yygnb.demo.config.SpringDocConfig

    @RequiredArgsConstructor
    @Configuration
    public class SpringDocConfig {
    
        private final DocInfo docInfo;
    
        @Bean
        public OpenAPI heroOpenAPI() {
            return new OpenAPI()
                    .info(new Info().title(docInfo.getTitle())
                            .description(docInfo.getDescription())
                            .version(docInfo.getVersion()))
                    .externalDocs(new ExternalDocumentation().description(docInfo.getWebsiteName())
                            .url(docInfo.getWebsiteUrl()));
        }
    
        @Bean
        public GroupedOpenApi publicApi() {
            return GroupedOpenApi.builder()
                    .group(docInfo.getTitle())
                    .pathsToMatch("/**")
                    .build();
        }
    }
    

    如果不添加这个 GroupedOpenApi 实例,knife4j ui就显示不出来。

    在 pom.xml 中引入 knife4j

    <properties>
    ...
        <knife4j-springdoc-ui.version>3.0.3knife4j-springdoc-ui.version>
    properties>
    
    <dependencies>
    ...
        <dependency>
            <groupId>com.github.xiaoymingroupId>
            <artifactId>knife4j-springdoc-uiartifactId>
            <version>${knife4j-springdoc-ui.version}version>
        dependency>
    dependencies>
    

    启动服务,访问:

    http://localhost:9099/doc.html
    

    显示 knife4j 的ui:

    image-20220804103201647

    image
    今日优雅哥(工\/youyacoder)学习结束,期待关注留言分享~~

  • 相关阅读:
    【C++】静态库.a和动态库.so文件的生成和使用
    Hadoop大数据平台搭建(超详细步骤)
    使用 Jenkins + Github + dokcer-compose 部署项目-实战篇
    学习渗透测试第一步:掌握信息收集
    机器视觉知识讲的深不如讲的透
    玩转NVIDIA Jetson (24)--- jetson docker非sudo使用
    业务应用前端实战经验总结
    高质量国产立体声编解码器CJC8988,Pin to Pin替代WM8988
    【计算机网络】 基于TCP的简单通讯(服务端)
    【业务功能篇97】微服务-springcloud-springboot-电商购物车模块-获取当前登录用户的购物车信息
  • 原文地址:https://www.cnblogs.com/youyacoder/p/16562539.html