From 38792c12a16fd4431d213aeba2ac8a96e766a6c8 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Sat, 20 Jan 2024 19:08:58 +0800 Subject: [PATCH] fix:fix swagger not working bug. (#1225) --- CHANGELOG.md | 1 + .../config/adapter/MockedConfigKVFile.java | 5 + .../ConditionalOnReflectRefreshTypeTest.java | 5 +- .../annotation/SpringValueProcessorTest.java | 5 +- .../pom.xml | 23 +-- .../contract/PolarisContractReporter.java | 76 ++++---- ...isContractPropertiesAutoConfiguration.java | 3 +- .../PolarisSwaggerAutoConfiguration.java | 108 ++++------- .../contract/filter/ApiDocServletFilter.java | 11 +- .../contract/filter/ApiDocWebFluxFilter.java | 5 +- .../polaris/contract/utils/PackageUtil.java | 89 +-------- .../api/AbstractOpenApiResourceUtil.java | 37 ++++ .../webflux/api/OpenApiWebFluxUtil.java | 36 ++++ .../webmvc/api/OpenApiWebMvcUtil.java | 35 ++++ ...WebMvcPatternsRequestConditionWrapper.java | 90 --------- .../spring/web/WebMvcRequestHandler.java | 175 ------------------ spring-cloud-tencent-dependencies/pom.xml | 20 +- .../src/main/resources/bootstrap.yml | 2 +- .../src/main/resources/bootstrap.yml | 2 +- .../src/main/resources/bootstrap.yml | 2 +- .../src/main/resources/bootstrap.yml | 2 +- 21 files changed, 233 insertions(+), 499 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java delete mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcPatternsRequestConditionWrapper.java delete mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcRequestHandler.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6420ac2..18ab8c138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,3 +21,4 @@ - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1192) - [fix:fix rule-based router when using RestTemplate.](https://github.com/Tencent/spring-cloud-tencent/pull/1201) - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1205) +- [fix:fix swagger not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1125) diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java index 59e89ebcc..bad8894a1 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java @@ -138,6 +138,11 @@ public boolean hasContent() { return false; } + @Override + public String getMd5() { + return null; + } + @Override public void addChangeListener(ConfigFileChangeListener configFileChangeListener) { diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java index e50eac0cc..ebde3e470 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.ServerSocket; +import java.util.Objects; import com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; @@ -67,7 +68,9 @@ static void beforeAll() { @AfterAll static void afterAll() throws IOException { - serverSocket.close(); + if (Objects.nonNull(serverSocket)) { + serverSocket.close(); + } } @Test diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java index d4d30c2f0..24439a72a 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java @@ -22,6 +22,7 @@ import java.lang.reflect.Method; import java.net.ServerSocket; import java.util.Collection; +import java.util.Objects; import java.util.Optional; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; @@ -71,7 +72,9 @@ static void beforeAll() { @AfterAll static void afterAll() throws IOException { - serverSocket.close(); + if (Objects.nonNull(serverSocket)) { + serverSocket.close(); + } } @Test diff --git a/spring-cloud-starter-tencent-polaris-contract/pom.xml b/spring-cloud-starter-tencent-polaris-contract/pom.xml index c17c92b32..39aca1001 100644 --- a/spring-cloud-starter-tencent-polaris-contract/pom.xml +++ b/spring-cloud-starter-tencent-polaris-contract/pom.xml @@ -36,28 +36,13 @@ - io.springfox - springfox-boot-starter - - - swagger-models - io.swagger - - - swagger-annotations - io.swagger - - + org.springdoc + springdoc-openapi-ui - io.swagger - swagger-models - - - - io.swagger - swagger-annotations + org.springdoc + springdoc-openapi-webflux-ui diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java index 1470136e8..bee9704fb 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java @@ -29,15 +29,16 @@ import com.tencent.polaris.api.plugin.server.InterfaceDescriptor; import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest; import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse; -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; +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 org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.service.Documentation; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.api.AbstractOpenApiResourceUtil; +import org.springdoc.webflux.api.OpenApiWebFluxUtil; +import org.springdoc.webmvc.api.OpenApiWebMvcUtil; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; @@ -52,18 +53,21 @@ public class PolarisContractReporter implements ApplicationListener { private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class); - private final ServiceModelToSwagger2Mapper swagger2Mapper; - private final DocumentationCache documentationCache; + + private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; + private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; private final PolarisContractProperties polarisContractProperties; private final ProviderAPI providerAPI; private final PolarisDiscoveryProperties polarisDiscoveryProperties; - public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper, - PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, PolarisDiscoveryProperties polarisDiscoveryProperties) { - this.swagger2Mapper = swagger2Mapper; - this.documentationCache = documentationCache; + public PolarisContractReporter(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, + PolarisDiscoveryProperties polarisDiscoveryProperties) { + this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource; + this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource; this.polarisContractProperties = polarisContractProperties; this.providerAPI = providerAPI; this.polarisDiscoveryProperties = polarisDiscoveryProperties; @@ -73,29 +77,37 @@ public PolarisContractReporter(DocumentationCache documentationCache, ServiceMod public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) { if (polarisContractProperties.isReportEnabled()) { try { - Documentation documentation = documentationCache.documentationByGroup(polarisContractProperties.getGroup()); - Swagger swagger = swagger2Mapper.mapDocumentation(documentation); - if (swagger != null) { + AbstractOpenApiResource openApiResource = null; + if (multipleOpenApiWebMvcResource != null) { + openApiResource = OpenApiWebMvcUtil.getOpenApiResourceOrThrow(multipleOpenApiWebMvcResource, polarisContractProperties.getGroup()); + } + else if (multipleOpenApiWebFluxResource != null) { + openApiResource = OpenApiWebFluxUtil.getOpenApiResourceOrThrow(multipleOpenApiWebFluxResource, polarisContractProperties.getGroup()); + } + OpenAPI openAPI = null; + if (openApiResource != null) { + openAPI = AbstractOpenApiResourceUtil.getOpenApi(openApiResource); + } + if (openAPI != null) { ReportServiceContractRequest request = new ReportServiceContractRequest(); request.setName(polarisDiscoveryProperties.getService()); request.setNamespace(polarisDiscoveryProperties.getNamespace()); request.setService(polarisDiscoveryProperties.getService()); request.setProtocol("http"); request.setVersion(polarisDiscoveryProperties.getVersion()); - List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger); + List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(openAPI); request.setInterfaceDescriptors(interfaceDescriptorList); ReportServiceContractResponse response = providerAPI.reportServiceContract(request); LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.", request.getNamespace(), request.getName(), request.getService(), request.getProtocol(), request.getVersion(), request.getInterfaceDescriptors().size()); if (LOG.isDebugEnabled()) { - String jsonValue = JacksonUtils.serialize2Json(swagger); + String jsonValue = JacksonUtils.serialize2Json(openAPI); LOG.debug("OpenApi json data: {}", jsonValue); } } else { - LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all() - .keySet(), polarisContractProperties.getGroup()); + LOG.warn("OpenAPI or json is null, group:{}", polarisContractProperties.getGroup()); } } catch (Throwable t) { @@ -104,11 +116,11 @@ public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEv } } - private List getInterfaceDescriptorFromSwagger(Swagger swagger) { + private List getInterfaceDescriptorFromSwagger(OpenAPI openAPI) { List interfaceDescriptorList = new ArrayList<>(); - Map paths = swagger.getPaths(); - for (Map.Entry p : paths.entrySet()) { - Path path = p.getValue(); + Paths paths = openAPI.getPaths(); + for (Map.Entry p : paths.entrySet()) { + PathItem path = p.getValue(); Map operationMap = getOperationMapFromPath(path); if (CollectionUtils.isEmpty(operationMap)) { continue; @@ -124,29 +136,29 @@ private List getInterfaceDescriptorFromSwagger(Swagger swag return interfaceDescriptorList; } - private Map getOperationMapFromPath(Path path) { + private Map getOperationMapFromPath(PathItem path) { Map operationMap = new HashMap<>(); if (path.getGet() != null) { - operationMap.put(HttpMethod.GET.name(), path.getGet()); + operationMap.put(PathItem.HttpMethod.GET.name(), path.getGet()); } if (path.getPut() != null) { - operationMap.put(HttpMethod.PUT.name(), path.getPut()); + operationMap.put(PathItem.HttpMethod.PUT.name(), path.getPut()); } if (path.getPost() != null) { - operationMap.put(HttpMethod.POST.name(), path.getPost()); + operationMap.put(PathItem.HttpMethod.POST.name(), path.getPost()); } if (path.getHead() != null) { - operationMap.put(HttpMethod.HEAD.name(), path.getHead()); + operationMap.put(PathItem.HttpMethod.HEAD.name(), path.getHead()); } if (path.getDelete() != null) { - operationMap.put(HttpMethod.DELETE.name(), path.getDelete()); + operationMap.put(PathItem.HttpMethod.DELETE.name(), path.getDelete()); } if (path.getPatch() != null) { - operationMap.put(HttpMethod.PATCH.name(), path.getPatch()); + operationMap.put(PathItem.HttpMethod.PATCH.name(), path.getPatch()); } if (path.getOptions() != null) { - operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions()); + operationMap.put(PathItem.HttpMethod.OPTIONS.name(), path.getOptions()); } return operationMap; diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java index d3e0edb35..a4d749cb2 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java @@ -17,13 +17,12 @@ package com.tencent.cloud.polaris.contract.config; -import javax.annotation.Nullable; - import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; /** * Auto configuration for Polaris contract properties. diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java index e0ace300c..75eee6c1d 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java @@ -17,11 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import java.time.LocalDate; -import java.util.Date; -import java.util.List; -import java.util.function.Predicate; - import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; @@ -30,13 +25,13 @@ import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter; import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter; import com.tencent.cloud.polaris.contract.utils.PackageUtil; -import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.service.Contact; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.SpringDocConfiguration; +import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource; +import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -45,6 +40,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.polaris.contract.utils.PackageUtil.SPLITTER; /** * Auto configuration for Polaris swagger. @@ -54,75 +53,48 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisEnabled @ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true) -@Import(OpenApiAutoConfiguration.class) +@Import(SpringDocConfiguration.class) public class PolarisSwaggerAutoConfiguration { - static { - // After springboot2.6.x, the default path matching strategy of spring MVC is changed from ANT_PATH_MATCHER - // mode to PATH_PATTERN_PARSER mode, causing an error. The solution is to switch to the original ANT_PATH_MATCHER mode. - System.setProperty("spring.mvc.pathmatch.matching-strategy", "ant-path-matcher"); - } - @Bean - public Docket polarisDocket(PolarisContractProperties polarisContractProperties) { - List> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath()); - List> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath()); + public GroupedOpenApi polarisGroupedOpenApi(PolarisContractProperties polarisContractProperties) { String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage()); - - Predicate basePathListOr = null; - for (Predicate basePathPredicate : basePathList) { - if (basePathListOr == null) { - basePathListOr = basePathPredicate; - } - else { - basePathListOr = basePathListOr.or(basePathPredicate); - } + String[] basePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getBasePath())) { + basePaths = polarisContractProperties.getBasePath().split(SPLITTER); } - - Predicate excludePathListOr = null; - for (Predicate excludePathPredicate : excludePathList) { - if (excludePathListOr == null) { - excludePathListOr = excludePathPredicate; - } - else { - excludePathListOr = excludePathListOr.or(excludePathPredicate); - } - } - - Predicate pathsPredicate = basePathListOr; - - if (excludePathListOr != null) { - excludePathListOr = excludePathListOr.negate(); - pathsPredicate = pathsPredicate.and(excludePathListOr); + String[] excludePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getExcludePath())) { + excludePaths = polarisContractProperties.getExcludePath().split(SPLITTER); } + return GroupedOpenApi.builder() + .packagesToScan(basePackage) + .pathsToMatch(basePaths) + .pathsToExclude(excludePaths) + .group(polarisContractProperties.getGroup()) + .build(); + } - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(PackageUtil.basePackage(basePackage)) - .paths(pathsPredicate) - .build() - .groupName(polarisContractProperties.getGroup()) - .enable(polarisContractProperties.isEnabled()) - .directModelSubstitute(LocalDate.class, Date.class) - .apiInfo(new ApiInfoBuilder() + @Bean + public OpenAPI polarisOpenAPI() { + return new OpenAPI() + .info(new Info() .title("Polaris Swagger API") .description("This is to show polaris api description.") - .license("BSD-3-Clause") - .licenseUrl("https://opensource.org/licenses/BSD-3-Clause") - .termsOfServiceUrl("") - .version("1.0.0") - .contact(new Contact("", "", "")) - .build()); + .license(new License().name("BSD-3-Clause").url("https://opensource.org/licenses/BSD-3-Clause")) + .version("1.0.0")); } @Bean - @ConditionalOnBean(Docket.class) + @ConditionalOnBean(OpenAPI.class) @ConditionalOnMissingBean - public PolarisContractReporter polarisContractReporter(DocumentationCache documentationCache, - ServiceModelToSwagger2Mapper swagger2Mapper, PolarisContractProperties polarisContractProperties, - PolarisSDKContextManager polarisSDKContextManager, PolarisDiscoveryProperties polarisDiscoveryProperties) { - return new PolarisContractReporter(documentationCache, swagger2Mapper, polarisContractProperties, - polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties); + public PolarisContractReporter polarisContractReporter( + @Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource, + @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, PolarisSDKContextManager polarisSDKContextManager, + PolarisDiscoveryProperties polarisDiscoveryProperties) { + return new PolarisContractReporter(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource, + polarisContractProperties, polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java index 38aa3d7c9..98e925024 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java @@ -26,7 +26,6 @@ import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; -import org.springframework.lang.NonNull; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX; @@ -51,11 +50,9 @@ public ApiDocServletFilter(PolarisContractProperties polarisContractProperties) } @Override - public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, - @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) - throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!polarisContractProperties.isExposure()) { - String path = httpServletRequest.getServletPath(); + String path = request.getServletPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || path.startsWith(SWAGGER_V3_API_DOC_URL) || path.startsWith(SWAGGER_UI_V2_URL) || @@ -63,11 +60,11 @@ public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, path.startsWith(SWAGGER_RESOURCE_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) { - httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); return; } } - filterChain.doFilter(httpServletRequest, httpServletResponse); + filterChain.doFilter(request, response); } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java index 7e7ea199a..ac9c23d8a 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java @@ -17,13 +17,13 @@ package com.tencent.cloud.polaris.contract.filter; - import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -42,6 +42,7 @@ * @author Haotian Zhang */ public class ApiDocWebFluxFilter implements WebFilter { + private final PolarisContractProperties polarisContractProperties; public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) { @@ -49,7 +50,7 @@ public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) } @Override - public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { + public Mono filter(ServerWebExchange serverWebExchange, @NonNull WebFilterChain webFilterChain) { if (!polarisContractProperties.isExposure()) { String path = serverWebExchange.getRequest().getURI().getPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java index 1ce380cf5..1afcb709d 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java @@ -17,26 +17,17 @@ package com.tencent.cloud.polaris.contract.utils; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.function.Predicate; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.tencent.cloud.polaris.contract.SwaggerContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.RequestHandler; -import springfox.documentation.builders.PathSelectors; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.util.StringUtils; -import static com.google.common.base.Optional.fromNullable; - /** * Util for package processing. * @@ -44,87 +35,15 @@ */ public final class PackageUtil { + /** + * splitter for property. + */ + public static final String SPLITTER = ","; private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class); - private static final String SPLITTER = ","; - private PackageUtil() { } - public static Predicate basePackage(String basePackage) { - return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false); - } - - public static Optional> declaringClass(RequestHandler input) { - if (input == null) { - return Optional.absent(); - } - return fromNullable(input.declaringClass()); - } - - public static Function, Boolean> handlerPackage(String basePackage, String splitter) { - return input -> { - try { - if (StringUtils.isEmpty(basePackage)) { - return false; - } - String[] packages = basePackage.trim().split(splitter); - // Loop to determine matching - for (String strPackage : packages) { - if (input == null) { - continue; - } - Package pkg = input.getPackage(); - if (pkg == null) { - continue; - } - String name = pkg.getName(); - if (StringUtils.isEmpty(name)) { - continue; - } - boolean isMatch = name.startsWith(strPackage); - if (isMatch) { - return true; - } - } - } - catch (Exception e) { - LOG.error("handler package error", e); - } - return false; - }; - } - - public static List> getExcludePathPredicates(String excludePath) { - List> excludePathList = new ArrayList<>(); - if (StringUtils.isEmpty(excludePath)) { - return excludePathList; - } - String[] exs = excludePath.split(SPLITTER); - for (String ex : exs) { - if (!StringUtils.isEmpty(ex)) { - excludePathList.add(PathSelectors.ant(ex)); - } - } - return excludePathList; - } - - public static List> getBasePathPredicates(String basePath) { - List> basePathList = new ArrayList<>(); - if (!StringUtils.isEmpty(basePath)) { - String[] bps = basePath.split(SPLITTER); - for (String bp : bps) { - if (!StringUtils.isEmpty(bp)) { - basePathList.add(PathSelectors.ant(bp)); - } - } - } - if (basePathList.isEmpty()) { - basePathList.add(PathSelectors.ant("/**")); - } - return basePathList; - } - public static String scanPackage(String configBasePackage) { String validScanPackage; // Externally configured scan package diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java new file mode 100644 index 000000000..8ef24531c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 org.springdoc.api; + +import java.util.Locale; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * Util for {@link AbstractOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class AbstractOpenApiResourceUtil { + + private AbstractOpenApiResourceUtil() { + } + + public static OpenAPI getOpenApi(AbstractOpenApiResource openApiResource) { + return openApiResource.getOpenApi(Locale.getDefault()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java new file mode 100644 index 000000000..8f146bff4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 org.springdoc.webflux.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebFluxUtil { + + private OpenApiWebFluxUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, String groupName) { + return multipleOpenApiWebFluxResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java new file mode 100644 index 000000000..6e4967cfb --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 org.springdoc.webmvc.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebMvcUtil { + private OpenApiWebMvcUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, String groupName) { + return multipleOpenApiWebMvcResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcPatternsRequestConditionWrapper.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcPatternsRequestConditionWrapper.java deleted file mode 100644 index d2be96b42..000000000 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcPatternsRequestConditionWrapper.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright 2015 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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 springfox.documentation.spring.web; - -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; - -import static springfox.documentation.spring.web.paths.Paths.maybeChompLeadingSlash; -import static springfox.documentation.spring.web.paths.Paths.maybeChompTrailingSlash; - -/** - * Modified to be compatible with spring-boot-actuator. - */ -public class WebMvcPatternsRequestConditionWrapper - implements springfox.documentation.spring.wrapper.PatternsRequestCondition { - private final String contextPath; - private final PatternsRequestCondition condition; - - public WebMvcPatternsRequestConditionWrapper( - String contextPath, - PatternsRequestCondition condition) { - - this.contextPath = contextPath; - this.condition = condition; - } - - @Override - public springfox.documentation.spring.wrapper.PatternsRequestCondition combine( - springfox.documentation.spring.wrapper.PatternsRequestCondition other) { - if (other instanceof WebMvcPatternsRequestConditionWrapper && !this.equals(other)) { - return new WebMvcPatternsRequestConditionWrapper( - contextPath, - condition.combine(((WebMvcPatternsRequestConditionWrapper) other).condition)); - } - return this; - } - - @Override - public Set getPatterns() { - // polaris add start - if (this.condition == null) { - return new HashSet<>(); - } - // polaris add end - return this.condition.getPatterns().stream() - .map(p -> String.format("%s/%s", maybeChompTrailingSlash(contextPath), maybeChompLeadingSlash(p))) - .collect(Collectors.toSet()); - } - - - @Override - public boolean equals(Object o) { - if (o instanceof WebMvcPatternsRequestConditionWrapper) { - return this.condition.equals(((WebMvcPatternsRequestConditionWrapper) o).condition); - } - return false; - } - - @Override - public int hashCode() { - return this.condition.hashCode(); - } - - - @Override - public String toString() { - return this.condition.toString(); - } -} - diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcRequestHandler.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcRequestHandler.java deleted file mode 100644 index 3f58ddcdb..000000000 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/springfox/documentation/spring/web/WebMvcRequestHandler.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Copyright 2016-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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 springfox.documentation.spring.web; - -import java.lang.annotation.Annotation; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.StringJoiner; - -import com.fasterxml.classmate.ResolvedType; -import springfox.documentation.RequestHandler; -import springfox.documentation.RequestHandlerKey; -import springfox.documentation.service.ResolvedMethodParameter; -import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; -import springfox.documentation.spring.wrapper.NameValueExpression; -import springfox.documentation.spring.wrapper.PatternsRequestCondition; - -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.mvc.method.RequestMappingInfo; - -import static java.util.Optional.ofNullable; - -/** - * Modified to be compatible with spring-boot-actuator. - */ -public class WebMvcRequestHandler implements RequestHandler { - private final String contextPath; - private final HandlerMethodResolver methodResolver; - private final RequestMappingInfo requestMapping; - private final HandlerMethod handlerMethod; - - public WebMvcRequestHandler( - String contextPath, - HandlerMethodResolver methodResolver, - RequestMappingInfo requestMapping, - HandlerMethod handlerMethod) { - this.contextPath = contextPath; - this.methodResolver = methodResolver; - this.requestMapping = requestMapping; - this.handlerMethod = handlerMethod; - } - - @Override - public HandlerMethod getHandlerMethod() { - return handlerMethod; - } - - @Override - public RequestHandler combine(RequestHandler other) { - return this; - } - - @Override - public Class declaringClass() { - return handlerMethod.getBeanType(); - } - - @Override - public boolean isAnnotatedWith(Class annotation) { - return null != AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation); - } - - @Override - public PatternsRequestCondition getPatternsCondition() { - return new WebMvcPatternsRequestConditionWrapper( - contextPath, - requestMapping.getPatternsCondition()); - } - - @Override - public String groupName() { - return ControllerNamingUtils.controllerNameAsGroup(handlerMethod); - } - - @Override - public String getName() { - return handlerMethod.getMethod().getName(); - } - - @Override - public Set supportedMethods() { - return requestMapping.getMethodsCondition().getMethods(); - } - - @Override - public Set produces() { - return requestMapping.getProducesCondition().getProducibleMediaTypes(); - } - - @Override - public Set consumes() { - return requestMapping.getConsumesCondition().getConsumableMediaTypes(); - } - - @Override - public Set> headers() { - return WebMvcNameValueExpressionWrapper.from(requestMapping.getHeadersCondition().getExpressions()); - } - - @Override - public Set> params() { - return WebMvcNameValueExpressionWrapper.from(requestMapping.getParamsCondition().getExpressions()); - } - - @Override - public Optional findAnnotation(Class annotation) { - return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation)); - } - - @Override - public RequestHandlerKey key() { - // polaris add start - Set patterns = new HashSet<>(); - if (requestMapping.getPatternsCondition() != null && requestMapping.getPatternsCondition() - .getPatterns() != null) { - patterns = requestMapping.getPatternsCondition().getPatterns(); - } - // polaris add end - return new RequestHandlerKey( - patterns, - requestMapping.getMethodsCondition().getMethods(), - requestMapping.getConsumesCondition().getConsumableMediaTypes(), - requestMapping.getProducesCondition().getProducibleMediaTypes()); - } - - @Override - public springfox.documentation.spring.wrapper.RequestMappingInfo getRequestMapping() { - return new WebMvcRequestMappingInfoWrapper(requestMapping); - } - - @Override - public List getParameters() { - return methodResolver.methodParameters(handlerMethod); - } - - @Override - public ResolvedType getReturnType() { - return methodResolver.methodReturnType(handlerMethod); - } - - @Override - public Optional findControllerAnnotation(Class annotation) { - return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), annotation)); - } - - @Override - public String toString() { - return new StringJoiner(", ", WebMvcRequestHandler.class.getSimpleName() + "{", "}") - .add("requestMapping=" + requestMapping) - .add("handlerMethod=" + handlerMethod) - .add("key=" + key()) - .toString(); - } -} diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 54e2ecb28..8aece8bff 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -76,7 +76,7 @@ 1.15.0-SNAPSHOT 32.0.1-jre 1.2.13 - 3.0.0 + 1.7.0 1.5.24 4.5.1 1.12.10 @@ -239,21 +239,15 @@ - io.springfox - springfox-boot-starter - ${springfox.swagger2.version} + org.springdoc + springdoc-openapi-ui + ${springdoc.version} - io.swagger - swagger-models - ${io.swagger.version} - - - - io.swagger - swagger-annotations - ${io.swagger.version} + org.springdoc + springdoc-openapi-webflux-ui + ${springdoc.version} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml index bf4d56b8f..e4c6ada51 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml @@ -14,7 +14,7 @@ spring: contract: exposure: true report: - enabled: false + enabled: true stat: enabled: true port: 28083 diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml index b5c7ec0bf..be96bfdcc 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml @@ -14,7 +14,7 @@ spring: contract: exposure: true report: - enabled: false + enabled: true stat: enabled: true port: 28084 diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml index b51cbdec5..7c538b8fa 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml @@ -17,7 +17,7 @@ spring: contract: exposure: true report: - enabled: false + enabled: true circuitbreaker: enabled: true stat: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index 0db7fd89a..52efd5e2d 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -21,7 +21,7 @@ spring: contract: exposure: true report: - enabled: false + enabled: true stat: enabled: true port: 28081