mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 22:57:19 +08:00 
			
		
		
		
	feat(api-doc): 增加对 BaseEnum 枚举接口的详细展示
This commit is contained in:
		| @@ -17,17 +17,28 @@ | |||||||
| package top.continew.starter.apidoc.autoconfigure; | package top.continew.starter.apidoc.autoconfigure; | ||||||
|  |  | ||||||
| import cn.hutool.core.map.MapUtil; | import cn.hutool.core.map.MapUtil; | ||||||
|  | import cn.hutool.core.util.ClassUtil; | ||||||
|  | import cn.hutool.core.util.StrUtil; | ||||||
|  | import com.fasterxml.jackson.databind.type.CollectionType; | ||||||
|  | import com.fasterxml.jackson.databind.type.SimpleType; | ||||||
| import io.swagger.v3.oas.models.Components; | import io.swagger.v3.oas.models.Components; | ||||||
| import io.swagger.v3.oas.models.OpenAPI; | import io.swagger.v3.oas.models.OpenAPI; | ||||||
| import io.swagger.v3.oas.models.info.Contact; | import io.swagger.v3.oas.models.info.Contact; | ||||||
| import io.swagger.v3.oas.models.info.Info; | import io.swagger.v3.oas.models.info.Info; | ||||||
| import io.swagger.v3.oas.models.info.License; | import io.swagger.v3.oas.models.info.License; | ||||||
|  | import io.swagger.v3.oas.models.media.Schema; | ||||||
| import io.swagger.v3.oas.models.security.SecurityRequirement; | import io.swagger.v3.oas.models.security.SecurityRequirement; | ||||||
| import io.swagger.v3.oas.models.security.SecurityScheme; | import io.swagger.v3.oas.models.security.SecurityScheme; | ||||||
| import jakarta.annotation.PostConstruct; | import jakarta.annotation.PostConstruct; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| import org.springdoc.core.customizers.GlobalOpenApiCustomizer; | import org.springdoc.core.configuration.SpringDocConfiguration; | ||||||
|  | import org.springdoc.core.customizers.*; | ||||||
|  | import org.springdoc.core.properties.SpringDocConfigProperties; | ||||||
|  | import org.springdoc.core.providers.JavadocProvider; | ||||||
|  | import org.springdoc.core.service.OpenAPIService; | ||||||
|  | import org.springdoc.core.service.SecurityService; | ||||||
|  | import org.springdoc.core.utils.PropertyResolverUtils; | ||||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||||
| @@ -37,11 +48,13 @@ import org.springframework.http.CacheControl; | |||||||
| import org.springframework.web.servlet.config.annotation.EnableWebMvc; | import org.springframework.web.servlet.config.annotation.EnableWebMvc; | ||||||
| import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||||||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||||||
|  | import top.continew.starter.apidoc.handler.OpenApiHandler; | ||||||
|  | import top.continew.starter.apidoc.util.EnumTypeUtils; | ||||||
| import top.continew.starter.core.autoconfigure.project.ProjectProperties; | import top.continew.starter.core.autoconfigure.project.ProjectProperties; | ||||||
|  | import top.continew.starter.core.enums.BaseEnum; | ||||||
| import top.continew.starter.core.util.GeneralPropertySourceFactory; | import top.continew.starter.core.util.GeneralPropertySourceFactory; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.*; | ||||||
| import java.util.Map; |  | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -51,7 +64,7 @@ import java.util.concurrent.TimeUnit; | |||||||
|  * @since 1.0.0 |  * @since 1.0.0 | ||||||
|  */ |  */ | ||||||
| @EnableWebMvc | @EnableWebMvc | ||||||
| @AutoConfiguration | @AutoConfiguration(before = SpringDocConfiguration.class) | ||||||
| @EnableConfigurationProperties(SpringDocExtensionProperties.class) | @EnableConfigurationProperties(SpringDocExtensionProperties.class) | ||||||
| @PropertySource(value = "classpath:default-api-doc.yml", factory = GeneralPropertySourceFactory.class) | @PropertySource(value = "classpath:default-api-doc.yml", factory = GeneralPropertySourceFactory.class) | ||||||
| public class SpringDocAutoConfiguration implements WebMvcConfigurer { | public class SpringDocAutoConfiguration implements WebMvcConfigurer { | ||||||
| @@ -127,6 +140,112 @@ public class SpringDocAutoConfiguration implements WebMvcConfigurer { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 自定义 openapi 处理器 | ||||||
|  |      */ | ||||||
|  |     @Bean | ||||||
|  |     public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI, | ||||||
|  |                                          SecurityService securityParser, | ||||||
|  |                                          SpringDocConfigProperties springDocConfigProperties, | ||||||
|  |                                          PropertyResolverUtils propertyResolverUtils, | ||||||
|  |                                          Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers, | ||||||
|  |                                          Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, | ||||||
|  |                                          Optional<JavadocProvider> javadocProvider) { | ||||||
|  |         return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 展示 枚举类型和值 | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     @Bean | ||||||
|  |     public ParameterCustomizer customParameterCustomizer() { | ||||||
|  |         return (parameterModel, methodParameter) -> { | ||||||
|  |             // 判断方法参数类型是否为 IBaseEnum 的子类型 | ||||||
|  |             if (ClassUtil.isAssignable(BaseEnum.class, methodParameter.getParameterType())) { | ||||||
|  |                 String description = parameterModel.getDescription(); | ||||||
|  |                 // TODO 会重复调用,有什么优雅的判读方式吗? | ||||||
|  |                 if (StrUtil.contains(description, "color:red")) { | ||||||
|  |                     return parameterModel; | ||||||
|  |                 } | ||||||
|  |                 Schema schema = parameterModel.getSchema(); | ||||||
|  |  | ||||||
|  |                 // 获取方法参数类型的所有枚举常量 | ||||||
|  |                 BaseEnum[] enumConstants = (BaseEnum[])methodParameter.getParameterType().getEnumConstants(); | ||||||
|  |                 List<String> list = new ArrayList<>(); | ||||||
|  |                 Map<Object, String> descMap = new HashMap<>(); | ||||||
|  |  | ||||||
|  |                 // 遍历枚举常量,获取其值和描述 | ||||||
|  |                 for (BaseEnum constant : enumConstants) { | ||||||
|  |                     list.add(constant.getValue().toString()); | ||||||
|  |                     descMap.put(constant.getValue(), constant.getDescription()); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // 枚举值类型 | ||||||
|  |                 String enumValueType = EnumTypeUtils.getEnumValueTypeAsString(methodParameter.getParameterType()); | ||||||
|  |                 schema.setType(enumValueType); | ||||||
|  |                 switch (enumValueType) { | ||||||
|  |                     case "integer" -> schema.setFormat("int32"); | ||||||
|  |                     case "long" -> schema.setFormat("int64"); | ||||||
|  |                     case "number" -> schema.setFormat("double"); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // 设置枚举值列表和描述 | ||||||
|  |                 schema.setEnum(list); | ||||||
|  |                 parameterModel.setDescription(description + "<span style='color:red'>" + descMap + "</span>"); | ||||||
|  |             } | ||||||
|  |             return parameterModel; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 展示 枚举类型和值 | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     @Bean | ||||||
|  |     public PropertyCustomizer customPropertyCustomizer() { | ||||||
|  |         return (schema, type) -> { | ||||||
|  |             Class<?> rawClass; | ||||||
|  |             // 获取原始类的类型 | ||||||
|  |             if (type.getType() instanceof SimpleType) { | ||||||
|  |                 rawClass = ((SimpleType)type.getType()).getRawClass(); | ||||||
|  |             } else if (type.getType() instanceof CollectionType) { | ||||||
|  |                 rawClass = ((CollectionType)type.getType()).getContentType().getRawClass(); | ||||||
|  |             } else { | ||||||
|  |                 rawClass = Object.class; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // 检查原始类是否实现了 IBaseEnum 接口 | ||||||
|  |             if (ClassUtil.isAssignable(BaseEnum.class, rawClass)) { | ||||||
|  |                 BaseEnum[] enumConstants = (BaseEnum[])rawClass.getEnumConstants(); | ||||||
|  |                 List<String> list = new ArrayList<>(); | ||||||
|  |                 Map<Object, String> descMap = new HashMap<>(); | ||||||
|  |                 // 遍历枚举常量,获取其值和描述 | ||||||
|  |                 for (BaseEnum constant : enumConstants) { | ||||||
|  |                     list.add(constant.getValue().toString()); | ||||||
|  |                     descMap.put(constant.getValue(), constant.getDescription()); | ||||||
|  |                 } | ||||||
|  |                 // 获取泛型类型 | ||||||
|  |                 String enumValueType = EnumTypeUtils.getEnumValueTypeAsString(rawClass); | ||||||
|  |                 schema.setType(enumValueType); | ||||||
|  |                 // 根据枚举值类型设置 schema 的格式 | ||||||
|  |                 switch (enumValueType) { | ||||||
|  |                     case "integer" -> schema.setFormat("int32"); | ||||||
|  |                     case "long" -> schema.setFormat("int64"); | ||||||
|  |                     case "number" -> schema.setFormat("double"); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // 设置枚举值列表和描述 | ||||||
|  |                 schema.setEnum(list); | ||||||
|  |                 schema.setDescription(schema.getDescription() + "<span style='color:red'>" + descMap + "</span>"); | ||||||
|  |                 return schema; | ||||||
|  |             } | ||||||
|  |             return schema; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @PostConstruct |     @PostConstruct | ||||||
|     public void postConstruct() { |     public void postConstruct() { | ||||||
|         log.debug("[ContiNew Starter] - Auto Configuration 'ApiDoc' completed initialization."); |         log.debug("[ContiNew Starter] - Auto Configuration 'ApiDoc' completed initialization."); | ||||||
|   | |||||||
| @@ -0,0 +1,286 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * <p> | ||||||
|  |  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * <p> | ||||||
|  |  * http://www.gnu.org/licenses/lgpl.html | ||||||
|  |  * <p> | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package top.continew.starter.apidoc.handler; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  | import cn.hutool.core.io.IoUtil; | ||||||
|  | import io.swagger.v3.core.jackson.TypeNameResolver; | ||||||
|  | import io.swagger.v3.core.util.AnnotationsUtils; | ||||||
|  | import io.swagger.v3.oas.annotations.tags.Tags; | ||||||
|  | import io.swagger.v3.oas.models.Components; | ||||||
|  | import io.swagger.v3.oas.models.OpenAPI; | ||||||
|  | import io.swagger.v3.oas.models.Operation; | ||||||
|  | import io.swagger.v3.oas.models.Paths; | ||||||
|  | import io.swagger.v3.oas.models.tags.Tag; | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.springdoc.core.customizers.OpenApiBuilderCustomizer; | ||||||
|  | import org.springdoc.core.customizers.ServerBaseUrlCustomizer; | ||||||
|  | import org.springdoc.core.properties.SpringDocConfigProperties; | ||||||
|  | import org.springdoc.core.providers.JavadocProvider; | ||||||
|  | import org.springdoc.core.service.OpenAPIService; | ||||||
|  | import org.springdoc.core.service.SecurityService; | ||||||
|  | import org.springdoc.core.utils.PropertyResolverUtils; | ||||||
|  | import org.springframework.context.ApplicationContext; | ||||||
|  | import org.springframework.core.annotation.AnnotatedElementUtils; | ||||||
|  | import org.springframework.util.CollectionUtils; | ||||||
|  | import org.springframework.web.method.HandlerMethod; | ||||||
|  |  | ||||||
|  | import java.io.StringReader; | ||||||
|  | import java.lang.reflect.Method; | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.Stream; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 自定义 openapi 处理器 对源码功能进行修改 增强使用 | ||||||
|  |  */ | ||||||
|  | @SuppressWarnings("all") | ||||||
|  | public class OpenApiHandler extends OpenAPIService { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Basic error controller. | ||||||
|  |      */ | ||||||
|  |     private static Class<?> basicErrorController; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Security parser. | ||||||
|  |      */ | ||||||
|  |     private final SecurityService securityParser; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Mappings map. | ||||||
|  |      */ | ||||||
|  |     private final Map<String, Object> mappingsMap = new HashMap<>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Springdoc tags. | ||||||
|  |      */ | ||||||
|  |     private final Map<HandlerMethod, Tag> springdocTags = new HashMap<>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Open api builder customisers. | ||||||
|  |      */ | ||||||
|  |     private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The server base URL customisers. | ||||||
|  |      */ | ||||||
|  |     private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Spring doc config properties. | ||||||
|  |      */ | ||||||
|  |     private final SpringDocConfigProperties springDocConfigProperties; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Cached open api map. | ||||||
|  |      */ | ||||||
|  |     private final Map<String, OpenAPI> cachedOpenAPI = new HashMap<>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Property resolver utils. | ||||||
|  |      */ | ||||||
|  |     private final PropertyResolverUtils propertyResolverUtils; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The javadoc provider. | ||||||
|  |      */ | ||||||
|  |     private final Optional<JavadocProvider> javadocProvider; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Context. | ||||||
|  |      */ | ||||||
|  |     private ApplicationContext context; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Open api. | ||||||
|  |      */ | ||||||
|  |     private OpenAPI openAPI; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Is servers present. | ||||||
|  |      */ | ||||||
|  |     private boolean isServersPresent; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The Server base url. | ||||||
|  |      */ | ||||||
|  |     private String serverBaseUrl; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Instantiates a new Open api builder. | ||||||
|  |      * | ||||||
|  |      * @param openAPI                   the open api | ||||||
|  |      * @param securityParser            the security parser | ||||||
|  |      * @param springDocConfigProperties the spring doc config properties | ||||||
|  |      * @param propertyResolverUtils     the property resolver utils | ||||||
|  |      * @param openApiBuilderCustomizers the open api builder customisers | ||||||
|  |      * @param serverBaseUrlCustomizers  the server base url customizers | ||||||
|  |      * @param javadocProvider           the javadoc provider | ||||||
|  |      */ | ||||||
|  |     public OpenApiHandler(Optional<OpenAPI> openAPI, | ||||||
|  |                           SecurityService securityParser, | ||||||
|  |                           SpringDocConfigProperties springDocConfigProperties, | ||||||
|  |                           PropertyResolverUtils propertyResolverUtils, | ||||||
|  |                           Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers, | ||||||
|  |                           Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers, | ||||||
|  |                           Optional<JavadocProvider> javadocProvider) { | ||||||
|  |         super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); | ||||||
|  |         if (openAPI.isPresent()) { | ||||||
|  |             this.openAPI = openAPI.get(); | ||||||
|  |             if (this.openAPI.getComponents() == null) | ||||||
|  |                 this.openAPI.setComponents(new Components()); | ||||||
|  |             if (this.openAPI.getPaths() == null) | ||||||
|  |                 this.openAPI.setPaths(new Paths()); | ||||||
|  |             if (!CollectionUtils.isEmpty(this.openAPI.getServers())) | ||||||
|  |                 this.isServersPresent = true; | ||||||
|  |         } | ||||||
|  |         this.propertyResolverUtils = propertyResolverUtils; | ||||||
|  |         this.securityParser = securityParser; | ||||||
|  |         this.springDocConfigProperties = springDocConfigProperties; | ||||||
|  |         this.openApiBuilderCustomisers = openApiBuilderCustomizers; | ||||||
|  |         this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; | ||||||
|  |         this.javadocProvider = javadocProvider; | ||||||
|  |         if (springDocConfigProperties.isUseFqn()) | ||||||
|  |             TypeNameResolver.std.setUseFqn(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) { | ||||||
|  |  | ||||||
|  |         Set<Tag> tags = new HashSet<>(); | ||||||
|  |         Set<String> tagsStr = new HashSet<>(); | ||||||
|  |  | ||||||
|  |         buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); | ||||||
|  |         buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); | ||||||
|  |  | ||||||
|  |         if (!CollectionUtils.isEmpty(tagsStr)) | ||||||
|  |             tagsStr = tagsStr.stream() | ||||||
|  |                 .map(str -> propertyResolverUtils.resolve(str, locale)) | ||||||
|  |                 .collect(Collectors.toSet()); | ||||||
|  |  | ||||||
|  |         if (springdocTags.containsKey(handlerMethod)) { | ||||||
|  |             Tag tag = springdocTags.get(handlerMethod); | ||||||
|  |             tagsStr.add(tag.getName()); | ||||||
|  |             if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { | ||||||
|  |                 openAPI.addTagsItem(tag); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!CollectionUtils.isEmpty(tagsStr)) { | ||||||
|  |             if (CollectionUtils.isEmpty(operation.getTags())) | ||||||
|  |                 operation.setTags(new ArrayList<>(tagsStr)); | ||||||
|  |             else { | ||||||
|  |                 Set<String> operationTagsSet = new HashSet<>(operation.getTags()); | ||||||
|  |                 operationTagsSet.addAll(tagsStr); | ||||||
|  |                 operation.getTags().clear(); | ||||||
|  |                 operation.getTags().addAll(operationTagsSet); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isAutoTagClasses(operation)) { | ||||||
|  |  | ||||||
|  |             if (javadocProvider.isPresent()) { | ||||||
|  |                 String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType()); | ||||||
|  |                 if (StringUtils.isNotBlank(description)) { | ||||||
|  |                     Tag tag = new Tag(); | ||||||
|  |  | ||||||
|  |                     // 自定义部分 修改使用java注释当tag名 | ||||||
|  |                     List<String> list = IoUtil.readLines(new StringReader(description), new ArrayList<>()); | ||||||
|  |                     // tag.setName(tagAutoName); | ||||||
|  |                     tag.setName(list.get(0)); | ||||||
|  |                     operation.addTagsItem(list.get(0)); | ||||||
|  |  | ||||||
|  |                     tag.setDescription(description); | ||||||
|  |                     if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { | ||||||
|  |                         openAPI.addTagsItem(tag); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName()); | ||||||
|  |                 operation.addTagsItem(tagAutoName); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!CollectionUtils.isEmpty(tags)) { | ||||||
|  |             // Existing tags | ||||||
|  |             List<Tag> openApiTags = openAPI.getTags(); | ||||||
|  |             if (!CollectionUtils.isEmpty(openApiTags)) | ||||||
|  |                 tags.addAll(openApiTags); | ||||||
|  |             openAPI.setTags(new ArrayList<>(tags)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Handle SecurityRequirement at operation level | ||||||
|  |         io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser | ||||||
|  |             .getSecurityRequirements(handlerMethod); | ||||||
|  |         if (securityRequirements != null) { | ||||||
|  |             if (securityRequirements.length == 0) | ||||||
|  |                 operation.setSecurity(Collections.emptyList()); | ||||||
|  |             else | ||||||
|  |                 securityParser.buildSecurityRequirement(securityRequirements, operation); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return operation; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void buildTagsFromMethod(Method method, Set<Tag> tags, Set<String> tagsStr, Locale locale) { | ||||||
|  |         // method tags | ||||||
|  |         Set<Tags> tagsSet = AnnotatedElementUtils.findAllMergedAnnotations(method, Tags.class); | ||||||
|  |         Set<io.swagger.v3.oas.annotations.tags.Tag> methodTags = tagsSet.stream() | ||||||
|  |             .flatMap(x -> Stream.of(x.value())) | ||||||
|  |             .collect(Collectors.toSet()); | ||||||
|  |         methodTags.addAll(AnnotatedElementUtils | ||||||
|  |             .findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class)); | ||||||
|  |         if (!CollectionUtils.isEmpty(methodTags)) { | ||||||
|  |             tagsStr.addAll(toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale))); | ||||||
|  |             List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags); | ||||||
|  |             addTags(allTags, tags, locale); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<Tag> tags, Locale locale) { | ||||||
|  |         Optional<Set<Tag>> optionalTagSet = AnnotationsUtils.getTags(sourceTags | ||||||
|  |             .toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true); | ||||||
|  |         optionalTagSet.ifPresent(tagsSet -> { | ||||||
|  |             tagsSet.forEach(tag -> { | ||||||
|  |                 tag.name(propertyResolverUtils.resolve(tag.getName(), locale)); | ||||||
|  |                 tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale)); | ||||||
|  |                 if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName()))) | ||||||
|  |                     tags.add(tag); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 将collection转化为Set集合,但是两者的泛型不同<br> | ||||||
|  |      * <B>{@code Collection<E>  ------>  Set<T> } </B> | ||||||
|  |      * | ||||||
|  |      * @param collection 需要转化的集合 | ||||||
|  |      * @param function   collection中的泛型转化为set泛型的lambda表达式 | ||||||
|  |      * @param <E>        collection中的泛型 | ||||||
|  |      * @param <T>        Set中的泛型 | ||||||
|  |      * @return 转化后的Set | ||||||
|  |      */ | ||||||
|  |     public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) { | ||||||
|  |         if (CollUtil.isEmpty(collection) || function == null) { | ||||||
|  |             return CollUtil.newHashSet(); | ||||||
|  |         } | ||||||
|  |         return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.toSet()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,69 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||||
|  |  * <p> | ||||||
|  |  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * <p> | ||||||
|  |  * http://www.gnu.org/licenses/lgpl.html | ||||||
|  |  * <p> | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package top.continew.starter.apidoc.util; | ||||||
|  |  | ||||||
|  | import top.continew.starter.core.enums.BaseEnum; | ||||||
|  |  | ||||||
|  | import java.lang.reflect.ParameterizedType; | ||||||
|  | import java.lang.reflect.Type; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 枚举类型工具 | ||||||
|  |  * | ||||||
|  |  * @Author echo | ||||||
|  |  * @date 2024/07/31 | ||||||
|  |  */ | ||||||
|  | public class EnumTypeUtils { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取enum值类型 | ||||||
|  |      * | ||||||
|  |      * @param enumClass enum class | ||||||
|  |      * @return {@link String } | ||||||
|  |      */ | ||||||
|  |     public static String getEnumValueTypeAsString(Class<?> enumClass) { | ||||||
|  |         try { | ||||||
|  |             // 获取枚举类实现的所有接口 | ||||||
|  |             Type[] interfaces = enumClass.getGenericInterfaces(); | ||||||
|  |             // 遍历所有接口 | ||||||
|  |             for (Type type : interfaces) { | ||||||
|  |                 // 检查接口是否为参数化类型 | ||||||
|  |                 if (type instanceof ParameterizedType parameterizedType) { | ||||||
|  |                     // 检查接口的原始类型是否为 BaseEnum | ||||||
|  |                     if (parameterizedType.getRawType() == BaseEnum.class) { | ||||||
|  |                         Type actualType = parameterizedType.getActualTypeArguments()[0]; | ||||||
|  |                         // 检查实际类型参数是否为类类型 | ||||||
|  |                         if (actualType instanceof Class<?> actualClass) { | ||||||
|  |                             if (actualClass == Integer.class) { | ||||||
|  |                                 return "integer"; | ||||||
|  |                             } else if (actualClass == Long.class) { | ||||||
|  |                                 return "long"; | ||||||
|  |                             } else if (actualClass == Double.class) { | ||||||
|  |                                 return "number"; | ||||||
|  |                             } else if (actualClass == String.class) { | ||||||
|  |                                 return "string"; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception e) { | ||||||
|  |             e.printStackTrace(); | ||||||
|  |         } | ||||||
|  |         return "string"; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 吴泽威
					吴泽威