自定义实现 Java17+SpringBoot3+OpenAPI+Knife4j Starter

文章目录

    • 前言
    • 正文
      • [1 创建starter项目](#1 创建starter项目)
        • [1.1 依赖文件](#1.1 依赖文件)
        • [1.2 配置信息](#1.2 配置信息)
      • [2 自定义starer代码开发](#2 自定义starer代码开发)
        • [2.1 配置字段的定义](#2.1 配置字段的定义)
        • [2.2 自动配置类](#2.2 自动配置类)
      • [3 验证starter](#3 验证starter)
        • [3.1 测试项目的配置](#3.1 测试项目的配置)
        • [3.2 功能配置 application.yml](#3.2 功能配置 application.yml)
        • [3.3 测试代码](#3.3 测试代码)
          • [3.3.1 实体类](#3.3.1 实体类)
          • [3.3.2 控制器1](#3.3.2 控制器1)
          • [3.3.2 控制器2](#3.3.2 控制器2)
      • [4 效果展示](#4 效果展示)
        • [4.1 主页](#4.1 主页)
        • [4.2 实体类列表](#4.2 实体类列表)
        • [4.3 自定义文档](#4.3 自定义文档)
        • [4.4 接口文档](#4.4 接口文档)
    • 附录
      • [1 参考文档](#1 参考文档)
      • [2 注意事项](#2 注意事项)
        • [2.1 测试项目git地址](#2.1 测试项目git地址)
        • [2.2 starter项目目录](#2.2 starter项目目录)

前言

一直以来,在接口文档这块没怎么尝试过比较新的技术点,使用的都是swagger2 和 低版本的 knife4j

本次就研究下在高版本的情况下,基于swagger的接口文档有什么变化。

本文基于以下环境:

组件 版本
Java 17
SpringBoot 3.2.5
knife4j-openapi3-jakarta-spring-boot-starter 4.5.0

正文

1 创建starter项目

创建一个Maven类型的SpringBoot项目,作为starter组件的开发。

1.1 依赖文件

Maven项目中,使用pom.xml文件来管理依赖。这里列举以下在starter项目中,使用到的依赖坐标。

此处指定了Java版本、Maven编译Java代码时使用的Java版本,并切设置项目的编码格式为UTF-8格式。

xml 复制代码
<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>3.2.5</spring-boot.version>
    <knife4j-openapi3-jakarta-version>4.5.0</knife4j-openapi3-jakarta-version>
</properties>
<dependencies>
<!-- https://www.mvncenter.com/search/org.springframework.boot/spring-boot-starter-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- https://www.mvncenter.com/search/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>${knife4j-openapi3-jakarta-version}</version>
</dependency>

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
1.2 配置信息

因为这个starter组件是基于SpringBoot3.x开发的,所以在自定义starter时,使用新的写法,不在直接使用spring.factories文件对自动配置类进行配置。

resources目录下,创建目录 META-INF/spring,然后创建名为org.springframework.boot.autoconfigure.AutoConfiguration.imports的文件备用。

2 自定义starer代码开发

自定义starter的开发,代码量不多,主要是一个自动配置类和配置字段的定义。

2.1 配置字段的定义
java 复制代码
package org.feng.basic.swagger.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * Swagger 配置属性
 *
 * @author feng
 */
@Data
@ConfigurationProperties(prefix = SwaggerProperties.PREFIX)
public class SwaggerProperties {

    public static final String PREFIX = "swagger.config";

    private String title;
    private String version;
    private String description;
    private String termsOfService;
    private String licenseName;
    private String licenseUrl;

    private Contact contact;

    @Data
    public static class Contact {
        private String name;
        private String url;
        private String email;
    }
}
2.2 自动配置类

使用注解 ConditionalOnProperty 来指定是否进行配置bean的加载。

主要条件是 knife4j.enable=true,当满足条件时,配置类中的内容生效。

除此之外,在文件org.springframework.boot.autoconfigure.AutoConfiguration.imports 中,添加自动配置类的全名(包名+类名)。

比如,我项目中的自动配置类会配置为:org.feng.basic.swagger.SwaggerAutoConfiguration

java 复制代码
package org.feng.basic.swagger;

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.feng.basic.swagger.properties.SwaggerProperties;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 * swagger自动配置类
 *
 * @author feng
 */
@ConditionalOnProperty(prefix = "knife4j", name = "enable", havingValue = SwaggerAutoConfiguration.TRUE, matchIfMissing = true)
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration {

    public static final String TRUE = "true";

    private final SwaggerProperties swaggerProperties;

    public SwaggerAutoConfiguration(@Autowired SwaggerProperties swaggerProperties) {
        this.swaggerProperties = swaggerProperties;
    }


    /**
     * 根据@Tag 上的排序,写入x-order
     *
     * @return the global open api customizer
     */
    @Bean
    public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
        return openApi -> {
//            if (openApi.getTags() != null) {
//                openApi.getTags().forEach(tag -> {
//                    Map<String, Object> map = new HashMap<>();
//                    map.put("x-order", ThreadLocalRandom.current().nextInt(0, 100));
//                    tag.setExtensions(map);
//                });
//            }
//            if (openApi.getPaths() != null) {
//                openApi.addExtension("x-test123", "333");
//                openApi.getPaths().addExtension("x-abb", ThreadLocalRandom.current().nextInt(0, 100));
//            }

        };
    }

    @Bean
    public OpenAPI openApi() {
        return new OpenAPI()
                .info(new Info()
                        .title(swaggerProperties.getTitle())
                        .description(swaggerProperties.getDescription())
                        .version(swaggerProperties.getVersion())
                        .termsOfService(swaggerProperties.getTermsOfService())
                        .contact(new Contact().name(swaggerProperties.getContact().getName())
                                .url(swaggerProperties.getContact().getUrl())
                                .email(swaggerProperties.getContact().getEmail()))
                        .license(new License().name(swaggerProperties.getLicenseName()).url(swaggerProperties.getLicenseUrl())));
    }
}

3 验证starter

在本地开发时,将 starter 项目进行 mvn install打包并上传jar到本地的maven仓库中。

随后,创建一个新项目,在新项目中使用刚刚写好的starter组件。起始就是引入它的maven坐标,这里的版本选择和starter保持一致。

3.1 测试项目的配置

在测试项目中,使用spring-boot-web组件。具体的pom.xml配置如下:

xml 复制代码
    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.2.5</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.feng</groupId>
            <artifactId>spring-boot-swagger-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>org.feng.SpringBootSwaggerStarterTestApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
3.2 功能配置 application.yml
yaml 复制代码
server:
  port: 17813
  servlet:
    context-path: /
spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB
  application:
    name: knife4j-spring-boot3-demo
springdoc:
  swagger-ui:
    path: /swagger-ui.html
    tags-sorter: alpha
    #operations-sorter: order
  api-docs:
    path: /v3/api-docs
  # 分组配置,对不同的包进行分组
  group-configs:
    - group: 'test1'
      display-name: '测试1'
      paths-to-match: '/**'
      packages-to-scan: org.feng.test1.controller
    - group: 'test2'
      display-name: '测试2'
      paths-to-match: '/**'
      packages-to-scan: org.feng.test2.controller
  default-flat-param-object: true

knife4j:
  enable: true
  setting:
    language: zh_cn
    swagger-model-name: 实体类列表
    # 是否在每个Debug调试栏后显示刷新变量按钮,默认不显示
    enableReloadCacheParameter: true
    # 是否开启界面中对某接口的版本控制,如果开启,后端变化后Ui界面会存在小蓝点
    enableVersion: true
    # 针对RequestMapping的接口请求类型,在不指定参数类型的情况下,如果不过滤,默认会显示7个类型的接口地址参数,如果开启此配置,默认展示一个Post类型的接口地址
    enableFilterMultipartApis: true
    # 是否开启动态参数调试功能
    enableDynamicParameter: true
    # 是否显示Footer
    enableFooter: false
    enableFooterCustom: true
    footerCustomContent: Apache License xx | Copyright  xxxx [xxxx-xxxx](https://xxxx.com/xxxx)
    # 自定义主页
    enable-home-custom: false
    home-custom-path: classpath:markdown/README.md

  documents:
    - name: 自定义文档1
      locations: classpath:markdown/*
      group: 测试1
    - name: 自定义文档2
      locations: classpath:markdown1/*
      group: 测试2
 # 启用简单的权限管理,访问接口文档需要登录
  basic:
    enable: true
    username: abc
    password: 123
  # http://www.knife4j.net/
  insight:
    enable: false
    service-name: boot3
    secret: S6CsnS8AnPVyb8vvChcdXm4R3p6A6KlAISxBg3IIEgk=
    server: http://localhost:10086
    namespace: spring3


swagger:
  config:
    title: '${spring.application.name}的在线文档'
    description: '在线文档'
    version: 'v1'
    terms-of-service: ''
    contact:
      name: 'feng'
      email: 'fengsoshuai@163.com'
      url: ''
    license-name: ''
    license-url: ''
3.3 测试代码
3.3.1 实体类
java 复制代码
package org.feng.model;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * TODO
 *
 * @author feng
 */
@Data
public class User implements Serializable {

    @Serial
    private static final long serialVersionUID = 7250829747040287299L;

    @Schema(title = "userId", description = "用户ID", defaultValue = "1")
    private Long id;

    @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
    private String name;

    @Schema(description = "注册日期")
    private LocalDateTime registerDate;
}
3.3.2 控制器1
java 复制代码
package org.feng.test1.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.feng.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * TODO
 *
 * @author feng
 */
@Tag(name = "test1")
@RestController
@RequestMapping("/test1")
public class Test1Controller {

    @Operation(summary = "获取详情")
    @GetMapping("/getOneById")
    public User getOneDetailById(@RequestParam(required = false) Integer id) {
        return null;
    }
}
3.3.2 控制器2
java 复制代码
package org.feng.test2.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.feng.model.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * TODO
 *
 * @author feng
 */
@Tag(name = "test2")
@RestController
@RequestMapping("/test2")
public class Test2Controller {
    @Operation(summary = "获取详情")
    @GetMapping("/getOneById")
    public User getOneDetailById(@RequestParam(required = false) Integer id) {
        return null;
    }
}

4 效果展示

启动项目后,访问链接:http://localhost:17813/doc.html#/home

4.1 主页
4.2 实体类列表
4.3 自定义文档
4.4 接口文档

附录

1 参考文档

2 注意事项

2.1 测试项目git地址

https://gitee.com/fengsoshuai/spring-boot-swagger-starter-test

注意:因为starter的代码和配置很少,就不单独建立仓库了。仓库只包含测试项目的代码。starter的代码和配置可以从本文中粘贴出来。

2.2 starter项目目录
相关推荐
靓仔建4 小时前
Asp.net core用Swashbuckle.AspNetCore库出现错误信息:No operations defined in spec!
后端·asp.net·swagger
whltaoin9 天前
Spring Boot Swagger3常用注解详解与实战
spring boot·注解·swagger
一刀到底2111 个月前
springboot3.3.5 集成elasticsearch8.12.2 ssl 通过 SSL bundle name 来实现
网络·elasticsearch·ssl·springboot3
awei09161 个月前
SpringBoot3中使用Caffeine缓存组件
java·缓存·springboot·springboot3
现在没有牛仔了1 个月前
SpringBoot项目集成Swagger指南
spring boot·后端·swagger
百锦再2 个月前
一文精通 Swagger 在 .NET 中的全方位配置与应用
后端·ui·.net·接口·配置·swagger·访问
杨DaB2 个月前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
lgx0406051122 个月前
基于.Net Framework4.5 Web API 引用Swagger
swagger·.net framework
尚学教辅学习资料2 个月前
SpringBoot3.x入门到精通系列:4.1 整合 MongoDB 详解
数据库·mongodb·springboot3
IT之家2 个月前
swagger文档生成html静态文档
swagger·openapi·离线文档