# Conflicts:
#	pom.xml
#	yudao-dependencies/pom.xml
#	yudao-framework/yudao-common/pom.xml
#	yudao-framework/yudao-spring-boot-starter-web/pom.xml
#	yudao-module-bpm/yudao-module-bpm-api/pom.xml
#	yudao-module-infra/yudao-module-infra-api/pom.xml
#	yudao-module-mall/yudao-module-product-api/pom.xml
#	yudao-module-mall/yudao-module-promotion-api/pom.xml
#	yudao-module-mall/yudao-module-statistics-api/pom.xml
#	yudao-module-mall/yudao-module-trade-api/pom.xml
#	yudao-module-member/yudao-module-member-api/pom.xml
#	yudao-module-pay/yudao-module-pay-api/pom.xml
#	yudao-module-system/yudao-module-system-api/pom.xml
pull/205/MERGE
YunaiV 2025-08-20 21:13:07 +08:00
commit a63587e8cb
18 changed files with 164 additions and 16 deletions

View File

@ -0,0 +1,146 @@
package cn.iocoder.yudao.framework.swagger.config;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.github.xiaoymin.knife4j.core.conf.ExtensionsConstants;
import com.github.xiaoymin.knife4j.core.conf.GlobalConstants;
import com.github.xiaoymin.knife4j.spring.configuration.Knife4jProperties;
import com.github.xiaoymin.knife4j.spring.configuration.Knife4jSetting;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.models.OpenAPI;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;
/**
*
*
* <a href="https://github.com/xiaoymin/knife4j/issues/913">Spring Boot 3.4 /v3/api-docs </a>
*
* @since 4.1.0
* @author <a href="xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
* 2022/12/11 22:40
*/
@Primary
@Configuration
@Slf4j
public class Knife4jOpenApiCustomizer extends com.github.xiaoymin.knife4j.spring.extension.Knife4jOpenApiCustomizer
implements GlobalOpenApiCustomizer {
final Knife4jProperties knife4jProperties;
final SpringDocConfigProperties properties;
public Knife4jOpenApiCustomizer(Knife4jProperties knife4jProperties, SpringDocConfigProperties properties) {
super(knife4jProperties,properties);
this.knife4jProperties = knife4jProperties;
this.properties = properties;
}
@Override
public void customise(OpenAPI openApi) {
if (knife4jProperties.isEnable()) {
Knife4jSetting setting = knife4jProperties.getSetting();
OpenApiExtensionResolver openApiExtensionResolver = new OpenApiExtensionResolver(setting, knife4jProperties.getDocuments());
// 解析初始化
openApiExtensionResolver.start();
Map<String, Object> objectMap = new HashMap<>();
objectMap.put(GlobalConstants.EXTENSION_OPEN_SETTING_NAME, setting);
objectMap.put(GlobalConstants.EXTENSION_OPEN_MARKDOWN_NAME, openApiExtensionResolver.getMarkdownFiles());
openApi.addExtension(GlobalConstants.EXTENSION_OPEN_API_NAME, objectMap);
addOrderExtension(openApi);
}
}
/**
* OpenAPI tags x-order
*
* @param openApi openApi
*/
private void addOrderExtension(OpenAPI openApi) {
if (CollectionUtils.isEmpty(properties.getGroupConfigs())) {
return;
}
// 获取包扫描路径
Set<String> packagesToScan =
properties.getGroupConfigs().stream()
.map(SpringDocConfigProperties.GroupConfig::getPackagesToScan)
.filter(toScan -> !CollectionUtils.isEmpty(toScan))
.flatMap(List::stream)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(packagesToScan)) {
return;
}
// 扫描包下被 ApiSupport 注解的 RestController Class
Set<Class<?>> classes = packagesToScan.stream()
.map(packageToScan -> scanPackageByAnnotation(packageToScan, RestController.class))
.flatMap(Set::stream)
.filter(clazz -> clazz.isAnnotationPresent(ApiSupport.class))
.collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(classes)) {
// ApiSupport oder 值存入 tagSortMap<Tag.name,ApiSupport.order>
Map<String, Integer> tagOrderMap = new HashMap<>();
classes.forEach(clazz -> {
Tag tag = getTag(clazz);
if (Objects.nonNull(tag)) {
ApiSupport apiSupport = clazz.getAnnotation(ApiSupport.class);
tagOrderMap.putIfAbsent(tag.name(), apiSupport.order());
}
});
// 往 openApi tags 字段添加 x-order 增强属性
if (openApi.getTags() != null) {
openApi.getTags().forEach(tag -> {
if (tagOrderMap.containsKey(tag.getName())) {
tag.addExtension(ExtensionsConstants.EXTENSION_ORDER, tagOrderMap.get(tag.getName()));
}
});
}
}
}
private Tag getTag(Class<?> clazz) {
// 从类上获取
Tag tag = clazz.getAnnotation(Tag.class);
if (Objects.isNull(tag)) {
// 从接口上获取
Class<?>[] interfaces = clazz.getInterfaces();
if (ArrayUtils.isNotEmpty(interfaces)) {
for (Class<?> interfaceClazz : interfaces) {
Tag anno = interfaceClazz.getAnnotation(Tag.class);
if (Objects.nonNull(anno)) {
tag = anno;
break;
}
}
}
}
return tag;
}
private Set<Class<?>> scanPackageByAnnotation(String packageName, final Class<? extends Annotation> annotationClass) {
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass));
Set<Class<?>> classes = new HashSet<>();
for (BeanDefinition beanDefinition : scanner.findCandidateComponents(packageName)) {
try {
Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
classes.add(clazz);
} catch (ClassNotFoundException ignore) {
}
}
return classes;
}
}

View File

@ -19,6 +19,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpHeaders;
@ -42,6 +43,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_
@ConditionalOnClass({OpenAPI.class})
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用
@Import(Knife4jOpenApiCustomizer.class)
public class YudaoSwaggerAutoConfiguration {
// ========== 全局 OpenAPI 配置 ==========

View File

@ -59,7 +59,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -54,7 +54,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn

View File

@ -63,7 +63,7 @@ springdoc:
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: false # TODO 芋艿需要关闭增强具体原因见https://github.com/xiaoymin/knife4j/issues/874
enable: true
setting:
language: zh_cn