diff --git a/continew-starter-api-doc/pom.xml b/continew-starter-api-doc/pom.xml index 0b5214ba..be55cab2 100644 --- a/continew-starter-api-doc/pom.xml +++ b/continew-starter-api-doc/pom.xml @@ -22,10 +22,11 @@ continew-starter-core - + - com.github.xiaoymin - knife4j-openapi3-jakarta-spring-boot-starter + top.nextdoc4j + nextdoc4j-springboot3-starter + \ No newline at end of file diff --git a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/autoconfigure/SpringDocAutoConfiguration.java b/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/autoconfigure/SpringDocAutoConfiguration.java index 6e106005..8b45e45c 100644 --- a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/autoconfigure/SpringDocAutoConfiguration.java +++ b/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/autoconfigure/SpringDocAutoConfiguration.java @@ -17,6 +17,7 @@ package top.continew.starter.apidoc.autoconfigure; import cn.hutool.core.map.MapUtil; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; @@ -29,32 +30,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.customizers.GlobalOpenApiCustomizer; -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.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; -import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import top.continew.starter.apidoc.handler.BaseEnumParameterHandler; -import top.continew.starter.apidoc.handler.OpenApiHandler; import top.continew.starter.core.autoconfigure.application.ApplicationProperties; import top.continew.starter.core.util.CollUtils; import top.continew.starter.core.util.GeneralPropertySourceFactory; import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; /** * API 文档自动配置 @@ -73,10 +63,6 @@ public class SpringDocAutoConfiguration implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/"); - registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/"); - registry.addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/") - .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic()); } /** @@ -139,20 +125,6 @@ public class SpringDocAutoConfiguration implements WebMvcConfigurer { }; } - /** - * 自定义 OpenApi 处理器 - */ - @Bean - public OpenAPIService openApiBuilder(Optional openAPI, - SecurityService securityParser, - SpringDocConfigProperties springDocConfigProperties, - PropertyResolverUtils propertyResolverUtils, - Optional> openApiBuilderCustomisers, - Optional> serverBaseUrlCustomisers, - Optional javadocProvider) { - return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); - } - /** * 自定义 BaseEnum 枚举参数配置(针对实现了 BaseEnum 的枚举,优化其枚举值和描述展示) * @@ -160,8 +132,8 @@ public class SpringDocAutoConfiguration implements WebMvcConfigurer { * @since 2.4.0 */ @Bean - public BaseEnumParameterHandler customParameterCustomizer() { - return new BaseEnumParameterHandler(); + public BaseEnumParameterHandler customParameterCustomizer(ObjectMapper mapper) { + return new BaseEnumParameterHandler(mapper); } @PostConstruct diff --git a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/BaseEnumParameterHandler.java b/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/BaseEnumParameterHandler.java index 1a6d6b63..5125e952 100644 --- a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/BaseEnumParameterHandler.java +++ b/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/BaseEnumParameterHandler.java @@ -18,19 +18,23 @@ package top.continew.starter.apidoc.handler; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ClassUtil; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.SimpleType; import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.jackson.ModelResolver; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.parameters.Parameter; import org.springdoc.core.customizers.ParameterCustomizer; -import org.springdoc.core.customizers.PropertyCustomizer; import org.springframework.core.MethodParameter; import top.continew.starter.apidoc.util.ApiDocUtils; import top.continew.starter.core.enums.BaseEnum; import java.lang.reflect.Type; import java.util.Arrays; +import java.util.Iterator; import java.util.List; /** @@ -42,7 +46,11 @@ import java.util.List; * @author echo * @since 2.5.2 */ -public class BaseEnumParameterHandler implements ParameterCustomizer, PropertyCustomizer { +public class BaseEnumParameterHandler extends ModelResolver implements ParameterCustomizer { + + public BaseEnumParameterHandler(ObjectMapper mapper) { + super(mapper); + } @Override public Parameter customize(Parameter parameterModel, MethodParameter methodParameter) { @@ -62,16 +70,18 @@ public class BaseEnumParameterHandler implements ParameterCustomizer, PropertyCu } @Override - public Schema customize(Schema schema, AnnotatedType type) { + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { + Schema resolve = super.resolve(type, context, chain); Class rawClass = resolveRawClass(type.getType()); // 判断是否为 BaseEnum 的子类型 if (!ClassUtil.isAssignable(BaseEnum.class, rawClass)) { - return schema; + return resolve; } + // 自定义参数描述并封装参数配置 - configureSchema(schema, rawClass); - schema.setDescription(appendEnumDescription(schema.getDescription(), rawClass)); - return schema; + configureSchema(resolve, rawClass); + resolve.setDescription(appendEnumDescription(resolve.getDescription(), rawClass)); + return resolve; } /** diff --git a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/OpenApiHandler.java b/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/OpenApiHandler.java deleted file mode 100644 index bf3eaa81..00000000 --- a/continew-starter-api-doc/src/main/java/top/continew/starter/apidoc/handler/OpenApiHandler.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - *

- * 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 - *

- * http://www.gnu.org/licenses/lgpl.html - *

- * 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.web.method.HandlerMethod; -import top.continew.starter.core.util.CollUtils; - -import java.io.StringReader; -import java.lang.reflect.Method; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * 自定义 OpenApi 处理器(对源码功能进行修改,增强使用) - * - * @author echo - * @since 2.4.0 - */ -@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 mappingsMap = new HashMap<>(); - - /** - * The Springdoc tags. - */ - private final Map springdocTags = new HashMap<>(); - - /** - * The Open api builder customisers. - */ - private final Optional> openApiBuilderCustomisers; - - /** - * The server base URL customisers. - */ - private final Optional> serverBaseUrlCustomizers; - - /** - * The Spring doc config properties. - */ - private final SpringDocConfigProperties springDocConfigProperties; - - /** - * The Cached open api map. - */ - private final Map cachedOpenAPI = new HashMap<>(); - - /** - * The Property resolver utils. - */ - private final PropertyResolverUtils propertyResolverUtils; - - /** - * The javadoc provider. - */ - private final Optional 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, - SecurityService securityParser, - SpringDocConfigProperties springDocConfigProperties, - PropertyResolverUtils propertyResolverUtils, - Optional> openApiBuilderCustomizers, - Optional> serverBaseUrlCustomizers, - Optional 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 (CollUtil.isNotEmpty(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 tags = new HashSet<>(); - Set tagsStr = new HashSet<>(); - - buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); - buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); - - if (CollUtil.isNotEmpty(tagsStr)) { - tagsStr = CollUtils.mapToSet(tagsStr, str -> propertyResolverUtils.resolve(str, locale)); - } - 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 (CollUtil.isNotEmpty(tagsStr)) { - if (CollUtil.isEmpty(operation.getTags())) { - operation.setTags(new ArrayList<>(tagsStr)); - } else { - Set 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 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 (CollUtil.isNotEmpty(tags)) { - // Existing tags - List openApiTags = openAPI.getTags(); - if (CollUtil.isNotEmpty(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 tags, Set tagsStr, Locale locale) { - // method tags - Set tagsSet = AnnotatedElementUtils.findAllMergedAnnotations(method, Tags.class); - Set 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 (CollUtil.isNotEmpty(methodTags)) { - tagsStr.addAll(CollUtils.mapToSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale))); - List allTags = new ArrayList<>(methodTags); - addTags(allTags, tags, locale); - } - } - - private void addTags(List sourceTags, Set tags, Locale locale) { - Optional> 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); - } - }); - }); - } -} diff --git a/continew-starter-api-doc/src/main/resources/default-api-doc.yml b/continew-starter-api-doc/src/main/resources/default-api-doc.yml index 566e964e..320c8574 100644 --- a/continew-starter-api-doc/src/main/resources/default-api-doc.yml +++ b/continew-starter-api-doc/src/main/resources/default-api-doc.yml @@ -10,8 +10,5 @@ springdoc: enabled: ${springdoc.swagger-ui.enabled} path: /v3/api-docs ## 接口文档增强配置 -knife4j: - enable: true - setting: - language: zh_cn - swagger-model-name: 实体类列表 +nextdoc4j: + enabled: true diff --git a/continew-starter-dependencies/pom.xml b/continew-starter-dependencies/pom.xml index 1d332f06..962fac69 100644 --- a/continew-starter-dependencies/pom.xml +++ b/continew-starter-dependencies/pom.xml @@ -62,7 +62,8 @@ 2.9.0 - 4.5.0 + 1.0.1 + 2.2.36 1.5.2 @@ -325,11 +326,11 @@ ${crane4j.version} - + - com.github.xiaoymin - knife4j-dependencies - ${knife4j.version} + top.nextdoc4j + nextdoc4j-bom + ${nextdoc4j.version} pom import @@ -422,6 +423,13 @@ ${commons-compress.version} + + + io.swagger.core.v3 + swagger-annotations-jakarta + ${swagger-annotations.version} + + top.continew.starter