引言
使用 JDK 21 版本创建的 Spring Boot 项目,在 SpringBoot3 整合 Swagger3 过程中遇到一些问题。网上很多关于 SpringBoot3 整合 Knife4j(Swagger3) 的步骤完全照着做会有很多兼容性问题。现将遇到的问题及解决方案记录如下。
SpringBoot3 整合 Knife4j(Swagger3) 关键点梳理
1. 添加/修改依赖
Spring Boot 3.x 必须使用 knife4j-openapi3-jakarta(Jakarta 命名空间)。
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
注意:不要使用旧版本的 knife4j-spring-boot-starter,否则会出现兼容性问题。
SpringBoot3.x 相比 SpringBoot2.x 特性上有很大改变,必须选择 SpringBoot3.x 版本兼容的 Knife4j 版本。
2. 添加配置文件
创建配置类以自定义 OpenAPI 信息、分组及全局响应码。
package com.Knife4j;
import cn.hutool.core.util.RandomUtil;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
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 io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
org.slf4j.Logger;
org.slf4j.LoggerFactory;
org.springdoc.core.customizers.GlobalOpenApiCustomizer;
org.springdoc.core.models.GroupedOpenApi;
org.springframework.context.annotation.Bean;
org.springframework.context.annotation.Configuration;
java.util.Map;
java.util.HashMap;
{
LoggerFactory.getLogger(Knife4jConfig.class);
;
;
;
;
;
;
;
GroupedOpenApi {
GroupedOpenApi.builder()
.group()
.displayName()
.packagesToScan()
.addOpenApiCustomizer(::setCustomStatusCode)
.build();
}
GroupedOpenApi {
GroupedOpenApi.builder()
.group()
.displayName()
.packagesToScan()
.addOpenApiCustomizer(::setCustomStatusCode)
.build();
}
GroupedOpenApi {
GroupedOpenApi.builder()
.group()
.displayName()
.packagesToScan()
.addOpenApiMethodFilter(method -> method.isAnnotationPresent(io.swagger.v3.oas.annotations.Operation.class))
.addOpenApiCustomizer(::setCustomStatusCode)
.build();
}
OpenAPI {
()
.info( ()
.title(API_INFO_TITLE)
.description(API_INFO_DESCRIPTION)
.version(API_INFO_VERSION)
.contact( ().name(API_INFO_NAME).email(API_INFO_EMAIL))
.license( ().name(API_INFO_LICENSE).url(SERVICE_URL)));
}
{
(openApi.getPaths() != ) {
openApi.getPaths();
(Map.Entry<String, PathItem> entry : paths.entrySet()) {
entry.getKey();
entry.getValue();
value.getPut();
value.getGet();
value.getDelete();
value.getPost();
(put != ) {
put.setResponses(handleResponses(put.getResponses()));
}
(get != ) {
get.setResponses(handleResponses(get.getResponses()));
}
(delete != ) {
delete.setResponses(handleResponses(delete.getResponses()));
}
(post != ) {
post.setResponses(handleResponses(post.getResponses()));
}
}
}
}
ApiResponses {
();
(Map.Entry<String, ApiResponse> entry : responses.entrySet()) {
entry.getKey();
entry.getValue();
(apiResponse != ) {
content = apiResponse.getContent();
;
}
}
Map<Integer, String> map = StatusCode.toMap();
(Map.Entry<Integer, String> entry : map.entrySet()) {
();
api.setContent(content);
api.description(entry.getValue());
responses.addApiResponse(entry.getKey() + , api);
}
responses;
}
GlobalOpenApiCustomizer {
openApi -> {
(openApi.getTags() != ) {
openApi.getTags().forEach(tag -> {
Map<String, Object> map = <>();
map.put(, RandomUtil.randomInt(, ));
tag.setExtensions(map);
});
}
(openApi.getPaths() != ) {
openApi.addExtension(, );
openApi.getPaths().addExtension(, RandomUtil.randomInt(, ));
}
};
}
OpenAPI {
()
.info( ()
.title()
.version()
.description()
.termsOfService()
.license( ().name()
.url()));
}
}



