自定义实现 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项目目录
相关推荐
测试者家园7 小时前
ChatGPT生成接口文档的方法与实践
软件测试·chatgpt·测试用例·接口测试·接口文档·ai赋能·用chatgpt做软件测试
Hello Dam2 天前
整合 Knife4j 于 Spring Cloud 网关:实现跨服务的 API 文档统一展示
后端·spring·spring cloud·knife4j
灰色孤星A3 天前
瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现
springboot·logback·swagger·瑞吉外卖·切面编程·表单校验·黑马程序员
亦世凡华、6 天前
从零开始:如何在.NET Core Web API中完美配置Swagger文档
开发语言·c#·swagger·.net core·web api
脸红ฅฅ*的思春期9 天前
Java安全—SpringBoot&Actuator&监控泄露&Swagger自动化
spring boot·自动化·swagger·actuator·java安全
God写代码没有注释10 天前
Swagger 调试,我不想再复制粘贴token啦~
swagger
好像是个likun13 天前
Java的Mvc整合Swagger的knife4框架
java·开发语言·mvc·swagger
CS软件开发框架19 天前
Swagger自动生成API接口注释和实体模型注释
java·服务器·前端·c#·.net·.netcore·swagger
IT界的奇葩24 天前
Springfox、Swagger 和 Springdoc
swagger
AH_HH1 个月前
Spring Boot 3.0废弃了JavaEE,改用了Jakarta EE
springboot3·javaee·jakarta ee