package com.aitori.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.util.*; import java.util.stream.Collectors; /** *

只是为了解决spring3.4版本的兼容问题

* *

增强扩展属性支持

* * @author xiaoymin@foxmail.com * 2022/12/11 22:40 * @since 4.1.0 */ @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) { log.debug("Knife4j OpenApiCustomizer"); if (knife4jProperties.isEnable()) { Knife4jSetting setting = knife4jProperties.getSetting(); OpenApiExtensionResolver openApiExtensionResolver = new OpenApiExtensionResolver(setting, knife4jProperties.getDocuments()); // 解析初始化 openApiExtensionResolver.start(); Map 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 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> classes = packagesToScan.stream() .map(this::scanPackageByAnnotation) .flatMap(Set::stream) .filter(clazz -> clazz.isAnnotationPresent(ApiSupport.class)) .collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(classes)) { // ApiSupport oder值存入tagSortMap Map 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> scanPackageByAnnotation( String packageName) { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(RestController.class)); Set> classes = new HashSet<>(); for (BeanDefinition beanDefinition : scanner.findCandidateComponents(packageName)) { try { Class clazz = Class.forName(beanDefinition.getBeanClassName()); classes.add(clazz); } catch (ClassNotFoundException ignore) { } } return classes; } }