文章目录
-
- 前言
- 正文
-
- [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 参考文档
- 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的代码和配置可以从本文中粘贴出来。