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

文章目录

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

前言

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

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

本文基于以下环境:

组件版本
Java17
SpringBoot3.2.5
knife4j-openapi3-jakarta-spring-boot-starter4.5.0

正文

1 创建starter项目

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

1.1 依赖文件

Maven项目中,使用pom.xml文件来管理依赖。这里列举以下在starter项目中,使用到的依赖坐标。
此处指定了Java版本、Maven编译Java代码时使用的Java版本,并切设置项目的编码格式为UTF-8格式。

<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 配置字段的定义
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

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配置如下:

    <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
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 实体类
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
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
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 参考文档

  • https://doc.xiaominfo.com/docs/quick-start#spring-boot-3
  • https://www.mvncenter.com/search/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter
  • https://www.mvncenter.com/search/org.springframework.boot/spring-boot-starter
  • https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/tree/master/knife4j-spring-boot3-demo
  • http://www.knife4j.net/

2 注意事项

2.1 测试项目git地址

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

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

2.2 starter项目目录

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/617636.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RuoYi-Vue-Plus (SpringCache、CacheManager、@Cacheable、缓存雪崩、击穿、穿透)

一、概述 1、SpringCache是Spring提供的一个缓存框架&#xff0c;在Spring3.1版本开始支持将缓存添加到现有的spring应用程序中&#xff0c;在4.1开始&#xff0c;缓存已支持JSR-107注释和更多自定义的选项。 2、SpringCache利用了AOP&#xff0c;实现了基于注解的缓存功能&…

LeetCode 题目 120:三角形最小路径和

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任字节跳动数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python&#xff0c;欢迎探讨交流 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题…

GPU prompt

提问&#xff1a; GPU是如何与CPU协调工作的&#xff1f; GPU也有缓存机制吗&#xff1f;有几层&#xff1f;速度差异是多少&#xff1f; GPU渲染流程有哪些阶段&#xff1f;他们的功能分别是什么&#xff1f; Early-Z技术是什么&#xff1f;发生在哪个阶段&#xff1f;这个…

7 Days yo Die 七日杀服务器开服联机教程

1、购买后登录服务器&#xff08;百度搜索莱卡云&#xff09;game.lcayun.com 进入控制面板后会出现正在安装的界面&#xff0c;安装时长约5分钟左右 安装成功后你就可以看到我们的控制台界面 复制服务器ip地址打开游戏➡加入游戏 有两种方法加入游戏 第一种方法&#xff1a;…

电商平台商品数据的价值在哪里?如何实现批量抓取?

一、电商平台商品数据的价值探秘 在数字经济的浪潮中&#xff0c;电商平台商品数据如同一座蕴藏着无尽宝藏的矿山&#xff0c;其价值远超过我们表面的认知。今天&#xff0c;就让我们一起揭开这座矿山的神秘面纱&#xff0c;探寻其中的奥秘。 首先&#xff0c;电商平台商品数…

Java反射(含静态代理模式、动态代理模式、类加载器以及JavaBean相关内容)

目录 1、什么是反射 2、Class类 3、通过Class类取得类信息/调用属性或方法 4、静态代理和动态代理 5.类加载器原理分析 6、JavaBean 1、什么是反射 Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息&#xff0c;从而操作类或对象的属性和方法。本质是JVM得…

c++:刷题必备 容器map的使用

文章目录 map的概念map的使用构造![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/30e9a697b50d47a591af6e9ae2bbb7d7.png)insert迭代器遍历 findoperator[]举例 map的概念 map是一个关联容器,里面的每一个位置pair,会存储两个值,一个是key,另一个是value. 我们可以…

【MySQL数据库开发设计规范】之表设计规范

欢迎点开这篇文章&#xff0c;自我介绍一下哈&#xff0c;本人姑苏老陈 &#xff0c;是一名JAVA开发老兵。 本文收录于 《MySQL数据库开发设计规范》专栏中&#xff0c;该专栏主要分享一些关于MySQL数据库开发设计相关的技术规范文章&#xff0c;定期更新&#xff0c;欢迎关注&…

使用 Docker 部署 VS Code in The Browser

1&#xff09;介绍 GitHub&#xff1a;https://github.com/coder/code-server 在日常学习工作中&#xff0c;Vscode 已成为我们首选的代码编辑器。然而&#xff0c;其局限性在于当我们从家到公司移动时&#xff0c;难以保持连续的编码体验。针对这一痛点&#xff0c;虽然市面上…

只需三步将Kimi接入微信公众号

今天我将手把手交大家如何把Kimi大模型接入微信公众号&#xff0c;创建属于你自己的公众号智能助理&#xff0c;让你的公众号具备智能对话、文件阅读、信息搜索等强大功能&#xff0c;同时提高用户互动率、减少人工客服压力等。 废话不多说&#xff0c;先来看看实际效果吧~ 一…

16 华三数据中心最流行的技术 M-LAG

STP和MTP&#xff08;第二十二课&#xff09;-CSDN博客 VRRP技术和浮动路由(第二十六课)_vrrp 浮动路由-CSDN博客 VRRP DHCP ACL NAT 网络核心路由技术综述 (第十课)-CSDN博客 04 交换机的IRF的配置-CSDN博客 1 M-LAG AI介绍 M-LAG&#xff08;Multi-Chassis Link Aggrega…

Electron学习笔记(一)

文章目录 相关笔记笔记说明 一、轻松入门 1、搭建开发环境2、创建窗口界面3、调试主进程 二、主进程和渲染进程1、进程互访2、渲染进程访问主进程类型3、渲染进程访问主进程自定义内容4、渲染进程向主进程发送消息5、主进程向渲染进程发送消息6、多个窗口的渲染进程接收主进程发…

【python】python淘宝交易数据分析可视化(源码+数据集)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

模型推导:BG/NBD(预测用户生命周期(CLV)模型)

CLV&#xff08;Customer Lifetime Value&#xff09;指的是客户生命周期价值&#xff0c;用以衡量客户在一段时间内对企业有多大的价值。企业对每个用户的流失与否、在未来时间是否会再次购买&#xff0c;还会再购买多少次才会流失等问题感兴趣&#xff0c;本文中的BG/NBD模型…

PostgreSQL数据库创建只读用户的权限安全隐患

PostgreSQL数据库模拟备库创建只读用户存在的权限安全隐患 default_transaction_read_only权限授权版本变更说明 看腻了就来听听视频演示吧&#xff1a;https://www.bilibili.com/video/BV1ZJ4m1578H/ default_transaction_read_only 创建只读用户&#xff0c;参照备库只读模…

第三步->手撕spring源码之基于Cglib实现实例化策略

为什么深入研究spring源码&#xff1f; 其实每一个程序员每天的工作都是一贯的CRUD 实现业务和需求完成的操作。几年这样的操作让我感觉在这方面要提神能力 光靠CRUD是绝对不可能的事情 CRUD只是满足你作为一个搬砖人而已。编程能力提升&#xff1f;其实更多的编程能力的提升是…

用 Supabase CLI 进行本地开发环境搭建

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;Supabase CLI&#xff08;1.1&#xff09;安装 Scoop&#xff08;1.2&#xff09;用 Scoop 安装 Supabase CLI &#xff08;二&#xff09;本地项目环境&#xff08;2.1&#xff09;初始化项目&#xff08;2…

Promise.all和 race

Promise.all() all方法可以完成并行任务&#xff0c; 它接收一个数组&#xff0c;数组的每一项都是一个promise对象。返回值&#xff1a; 成功时&#xff1a;当数组中所有的promise的状态都达到resolved的时候&#xff0c;就返回包含所有 Promise 结果的数组&#xff0c;并且…

【C++】————类与对象(上)-基础知识

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 类的两种定义方式&#xff1a; 成员变量命名规则的建议&#xff1a; 4.类的访问限定符及封装 4.1 访问限定符 ​编辑 【面试题】问题&#xff1a;C中struct和class的区别是什么&#xff1f; 4.2 封装 【面试…

数据分析中大数据和云计算

大数据和云计算 前言一、大数据二、大数据定义三、数据存储单位四、大数据存储技术五、大数据应用技术六、大数据特征七、数据容量八、数据类型的多样性结构化数据半结构化数据非结构化数据 九、获取数据的速度十、可变性十一、真实性十二、复杂性十三、价值十四、云计算十五、…