fix:fix swagger not working bug. (#1225)

pull/1258/head
Haotian Zhang 10 months ago committed by GitHub
parent dd56d3cbf1
commit 38792c12a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -21,3 +21,4 @@
- [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1192) - [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 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 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)

@ -138,6 +138,11 @@ public class MockedConfigKVFile implements ConfigKVFile {
return false; return false;
} }
@Override
public String getMd5() {
return null;
}
@Override @Override
public void addChangeListener(ConfigFileChangeListener configFileChangeListener) { public void addChangeListener(ConfigFileChangeListener configFileChangeListener) {

@ -20,6 +20,7 @@ package com.tencent.cloud.polaris.config.condition;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.Objects;
import com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration;
import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration;
@ -67,7 +68,9 @@ public class ConditionalOnReflectRefreshTypeTest {
@AfterAll @AfterAll
static void afterAll() throws IOException { static void afterAll() throws IOException {
serverSocket.close(); if (Objects.nonNull(serverSocket)) {
serverSocket.close();
}
} }
@Test @Test

@ -22,6 +22,7 @@ import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.Collection; import java.util.Collection;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration;
@ -71,7 +72,9 @@ public class SpringValueProcessorTest {
@AfterAll @AfterAll
static void afterAll() throws IOException { static void afterAll() throws IOException {
serverSocket.close(); if (Objects.nonNull(serverSocket)) {
serverSocket.close();
}
} }
@Test @Test

@ -36,28 +36,13 @@
<!-- Spring cloud dependencies start --> <!-- Spring cloud dependencies start -->
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>org.springdoc</groupId>
<artifactId>springfox-boot-starter</artifactId> <artifactId>springdoc-openapi-ui</artifactId>
<exclusions>
<exclusion>
<artifactId>swagger-models</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
<exclusion>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>org.springdoc</groupId>
<artifactId>swagger-models</artifactId> <artifactId>springdoc-openapi-webflux-ui</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency> </dependency>
<dependency> <dependency>

@ -29,15 +29,16 @@ import com.tencent.polaris.api.core.ProviderAPI;
import com.tencent.polaris.api.plugin.server.InterfaceDescriptor; import com.tencent.polaris.api.plugin.server.InterfaceDescriptor;
import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest; import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest;
import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse; import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse;
import io.swagger.models.HttpMethod; import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.models.Operation; import io.swagger.v3.oas.models.Operation;
import io.swagger.models.Path; import io.swagger.v3.oas.models.PathItem;
import io.swagger.models.Swagger; import io.swagger.v3.oas.models.Paths;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import springfox.documentation.service.Documentation; import org.springdoc.api.AbstractOpenApiResource;
import springfox.documentation.spring.web.DocumentationCache; import org.springdoc.api.AbstractOpenApiResourceUtil;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; import org.springdoc.webflux.api.OpenApiWebFluxUtil;
import org.springdoc.webmvc.api.OpenApiWebMvcUtil;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
@ -52,18 +53,21 @@ import org.springframework.util.CollectionUtils;
public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> { public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> {
private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class); 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 PolarisContractProperties polarisContractProperties;
private final ProviderAPI providerAPI; private final ProviderAPI providerAPI;
private final PolarisDiscoveryProperties polarisDiscoveryProperties; private final PolarisDiscoveryProperties polarisDiscoveryProperties;
public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper, public PolarisContractReporter(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource,
PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, PolarisDiscoveryProperties polarisDiscoveryProperties) { org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource,
this.swagger2Mapper = swagger2Mapper; PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI,
this.documentationCache = documentationCache; PolarisDiscoveryProperties polarisDiscoveryProperties) {
this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource;
this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource;
this.polarisContractProperties = polarisContractProperties; this.polarisContractProperties = polarisContractProperties;
this.providerAPI = providerAPI; this.providerAPI = providerAPI;
this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryProperties = polarisDiscoveryProperties;
@ -73,29 +77,37 @@ public class PolarisContractReporter implements ApplicationListener<ApplicationR
public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) { public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) {
if (polarisContractProperties.isReportEnabled()) { if (polarisContractProperties.isReportEnabled()) {
try { try {
Documentation documentation = documentationCache.documentationByGroup(polarisContractProperties.getGroup()); AbstractOpenApiResource openApiResource = null;
Swagger swagger = swagger2Mapper.mapDocumentation(documentation); if (multipleOpenApiWebMvcResource != null) {
if (swagger != 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(); ReportServiceContractRequest request = new ReportServiceContractRequest();
request.setName(polarisDiscoveryProperties.getService()); request.setName(polarisDiscoveryProperties.getService());
request.setNamespace(polarisDiscoveryProperties.getNamespace()); request.setNamespace(polarisDiscoveryProperties.getNamespace());
request.setService(polarisDiscoveryProperties.getService()); request.setService(polarisDiscoveryProperties.getService());
request.setProtocol("http"); request.setProtocol("http");
request.setVersion(polarisDiscoveryProperties.getVersion()); request.setVersion(polarisDiscoveryProperties.getVersion());
List<InterfaceDescriptor> interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger); List<InterfaceDescriptor> interfaceDescriptorList = getInterfaceDescriptorFromSwagger(openAPI);
request.setInterfaceDescriptors(interfaceDescriptorList); request.setInterfaceDescriptors(interfaceDescriptorList);
ReportServiceContractResponse response = providerAPI.reportServiceContract(request); ReportServiceContractResponse response = providerAPI.reportServiceContract(request);
LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.", LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.",
request.getNamespace(), request.getName(), request.getService(), request.getProtocol(), request.getNamespace(), request.getName(), request.getService(), request.getProtocol(),
request.getVersion(), request.getInterfaceDescriptors().size()); request.getVersion(), request.getInterfaceDescriptors().size());
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
String jsonValue = JacksonUtils.serialize2Json(swagger); String jsonValue = JacksonUtils.serialize2Json(openAPI);
LOG.debug("OpenApi json data: {}", jsonValue); LOG.debug("OpenApi json data: {}", jsonValue);
} }
} }
else { else {
LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all() LOG.warn("OpenAPI or json is null, group:{}", polarisContractProperties.getGroup());
.keySet(), polarisContractProperties.getGroup());
} }
} }
catch (Throwable t) { catch (Throwable t) {
@ -104,11 +116,11 @@ public class PolarisContractReporter implements ApplicationListener<ApplicationR
} }
} }
private List<InterfaceDescriptor> getInterfaceDescriptorFromSwagger(Swagger swagger) { private List<InterfaceDescriptor> getInterfaceDescriptorFromSwagger(OpenAPI openAPI) {
List<InterfaceDescriptor> interfaceDescriptorList = new ArrayList<>(); List<InterfaceDescriptor> interfaceDescriptorList = new ArrayList<>();
Map<String, Path> paths = swagger.getPaths(); Paths paths = openAPI.getPaths();
for (Map.Entry<String, Path> p : paths.entrySet()) { for (Map.Entry<String, PathItem> p : paths.entrySet()) {
Path path = p.getValue(); PathItem path = p.getValue();
Map<String, Operation> operationMap = getOperationMapFromPath(path); Map<String, Operation> operationMap = getOperationMapFromPath(path);
if (CollectionUtils.isEmpty(operationMap)) { if (CollectionUtils.isEmpty(operationMap)) {
continue; continue;
@ -124,29 +136,29 @@ public class PolarisContractReporter implements ApplicationListener<ApplicationR
return interfaceDescriptorList; return interfaceDescriptorList;
} }
private Map<String, Operation> getOperationMapFromPath(Path path) { private Map<String, Operation> getOperationMapFromPath(PathItem path) {
Map<String, Operation> operationMap = new HashMap<>(); Map<String, Operation> operationMap = new HashMap<>();
if (path.getGet() != null) { if (path.getGet() != null) {
operationMap.put(HttpMethod.GET.name(), path.getGet()); operationMap.put(PathItem.HttpMethod.GET.name(), path.getGet());
} }
if (path.getPut() != null) { if (path.getPut() != null) {
operationMap.put(HttpMethod.PUT.name(), path.getPut()); operationMap.put(PathItem.HttpMethod.PUT.name(), path.getPut());
} }
if (path.getPost() != null) { if (path.getPost() != null) {
operationMap.put(HttpMethod.POST.name(), path.getPost()); operationMap.put(PathItem.HttpMethod.POST.name(), path.getPost());
} }
if (path.getHead() != null) { if (path.getHead() != null) {
operationMap.put(HttpMethod.HEAD.name(), path.getHead()); operationMap.put(PathItem.HttpMethod.HEAD.name(), path.getHead());
} }
if (path.getDelete() != null) { if (path.getDelete() != null) {
operationMap.put(HttpMethod.DELETE.name(), path.getDelete()); operationMap.put(PathItem.HttpMethod.DELETE.name(), path.getDelete());
} }
if (path.getPatch() != null) { if (path.getPatch() != null) {
operationMap.put(HttpMethod.PATCH.name(), path.getPatch()); operationMap.put(PathItem.HttpMethod.PATCH.name(), path.getPatch());
} }
if (path.getOptions() != null) { if (path.getOptions() != null) {
operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions()); operationMap.put(PathItem.HttpMethod.OPTIONS.name(), path.getOptions());
} }
return operationMap; return operationMap;

@ -17,13 +17,12 @@
package com.tencent.cloud.polaris.contract.config; package com.tencent.cloud.polaris.contract.config;
import javax.annotation.Nullable;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
/** /**
* Auto configuration for Polaris contract properties. * Auto configuration for Polaris contract properties.

@ -17,11 +17,6 @@
package com.tencent.cloud.polaris.contract.config; 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.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
@ -30,13 +25,13 @@ import com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener;
import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter; import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter;
import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter; import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter;
import com.tencent.cloud.polaris.contract.utils.PackageUtil; import com.tencent.cloud.polaris.contract.utils.PackageUtil;
import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration; import io.swagger.v3.oas.models.OpenAPI;
import springfox.documentation.builders.ApiInfoBuilder; import io.swagger.v3.oas.models.info.Info;
import springfox.documentation.service.Contact; import io.swagger.v3.oas.models.info.License;
import springfox.documentation.spi.DocumentationType; import org.springdoc.core.GroupedOpenApi;
import springfox.documentation.spring.web.DocumentationCache; import org.springdoc.core.SpringDocConfiguration;
import springfox.documentation.spring.web.plugins.Docket; import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -45,6 +40,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; 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. * Auto configuration for Polaris swagger.
@ -54,75 +53,48 @@ import org.springframework.context.annotation.Import;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled @ConditionalOnPolarisEnabled
@ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true)
@Import(OpenApiAutoConfiguration.class) @Import(SpringDocConfiguration.class)
public class PolarisSwaggerAutoConfiguration { 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 @Bean
public Docket polarisDocket(PolarisContractProperties polarisContractProperties) { public GroupedOpenApi polarisGroupedOpenApi(PolarisContractProperties polarisContractProperties) {
List<Predicate<String>> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath());
List<Predicate<String>> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath());
String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage()); String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage());
String[] basePaths = {};
Predicate<String> basePathListOr = null; if (StringUtils.hasText(polarisContractProperties.getBasePath())) {
for (Predicate<String> basePathPredicate : basePathList) { basePaths = polarisContractProperties.getBasePath().split(SPLITTER);
if (basePathListOr == null) {
basePathListOr = basePathPredicate;
}
else {
basePathListOr = basePathListOr.or(basePathPredicate);
}
} }
String[] excludePaths = {};
Predicate<String> excludePathListOr = null; if (StringUtils.hasText(polarisContractProperties.getExcludePath())) {
for (Predicate<String> excludePathPredicate : excludePathList) { excludePaths = polarisContractProperties.getExcludePath().split(SPLITTER);
if (excludePathListOr == null) {
excludePathListOr = excludePathPredicate;
}
else {
excludePathListOr = excludePathListOr.or(excludePathPredicate);
}
}
Predicate<String> pathsPredicate = basePathListOr;
if (excludePathListOr != null) {
excludePathListOr = excludePathListOr.negate();
pathsPredicate = pathsPredicate.and(excludePathListOr);
} }
return GroupedOpenApi.builder()
.packagesToScan(basePackage)
.pathsToMatch(basePaths)
.pathsToExclude(excludePaths)
.group(polarisContractProperties.getGroup())
.build();
}
return new Docket(DocumentationType.SWAGGER_2) @Bean
.select() public OpenAPI polarisOpenAPI() {
.apis(PackageUtil.basePackage(basePackage)) return new OpenAPI()
.paths(pathsPredicate) .info(new Info()
.build()
.groupName(polarisContractProperties.getGroup())
.enable(polarisContractProperties.isEnabled())
.directModelSubstitute(LocalDate.class, Date.class)
.apiInfo(new ApiInfoBuilder()
.title("Polaris Swagger API") .title("Polaris Swagger API")
.description("This is to show polaris api description.") .description("This is to show polaris api description.")
.license("BSD-3-Clause") .license(new License().name("BSD-3-Clause").url("https://opensource.org/licenses/BSD-3-Clause"))
.licenseUrl("https://opensource.org/licenses/BSD-3-Clause") .version("1.0.0"));
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("", "", ""))
.build());
} }
@Bean @Bean
@ConditionalOnBean(Docket.class) @ConditionalOnBean(OpenAPI.class)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PolarisContractReporter polarisContractReporter(DocumentationCache documentationCache, public PolarisContractReporter polarisContractReporter(
ServiceModelToSwagger2Mapper swagger2Mapper, PolarisContractProperties polarisContractProperties, @Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource,
PolarisSDKContextManager polarisSDKContextManager, PolarisDiscoveryProperties polarisDiscoveryProperties) { @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource,
return new PolarisContractReporter(documentationCache, swagger2Mapper, polarisContractProperties, PolarisContractProperties polarisContractProperties, PolarisSDKContextManager polarisSDKContextManager,
polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties); PolarisDiscoveryProperties polarisDiscoveryProperties) {
return new PolarisContractReporter(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource,
polarisContractProperties, polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties);
} }
@Bean @Bean

@ -26,7 +26,6 @@ import javax.servlet.http.HttpServletResponse;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX; import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX;
@ -51,11 +50,9 @@ public class ApiDocServletFilter extends OncePerRequestFilter {
} }
@Override @Override
public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
@NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain)
throws ServletException, IOException {
if (!polarisContractProperties.isExposure()) { if (!polarisContractProperties.isExposure()) {
String path = httpServletRequest.getServletPath(); String path = request.getServletPath();
if (path.startsWith(SWAGGER_V2_API_DOC_URL) || if (path.startsWith(SWAGGER_V2_API_DOC_URL) ||
path.startsWith(SWAGGER_V3_API_DOC_URL) || path.startsWith(SWAGGER_V3_API_DOC_URL) ||
path.startsWith(SWAGGER_UI_V2_URL) || path.startsWith(SWAGGER_UI_V2_URL) ||
@ -63,11 +60,11 @@ public class ApiDocServletFilter extends OncePerRequestFilter {
path.startsWith(SWAGGER_RESOURCE_PREFIX) || path.startsWith(SWAGGER_RESOURCE_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) { path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return; return;
} }
} }
filterChain.doFilter(httpServletRequest, httpServletResponse); filterChain.doFilter(request, response);
} }
} }

@ -17,13 +17,13 @@
package com.tencent.cloud.polaris.contract.filter; package com.tencent.cloud.polaris.contract.filter;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
@ -42,6 +42,7 @@ import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_W
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class ApiDocWebFluxFilter implements WebFilter { public class ApiDocWebFluxFilter implements WebFilter {
private final PolarisContractProperties polarisContractProperties; private final PolarisContractProperties polarisContractProperties;
public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) { public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) {
@ -49,7 +50,7 @@ public class ApiDocWebFluxFilter implements WebFilter {
} }
@Override @Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { public Mono<Void> filter(ServerWebExchange serverWebExchange, @NonNull WebFilterChain webFilterChain) {
if (!polarisContractProperties.isExposure()) { if (!polarisContractProperties.isExposure()) {
String path = serverWebExchange.getRequest().getURI().getPath(); String path = serverWebExchange.getRequest().getURI().getPath();
if (path.startsWith(SWAGGER_V2_API_DOC_URL) || if (path.startsWith(SWAGGER_V2_API_DOC_URL) ||

@ -17,26 +17,17 @@
package com.tencent.cloud.polaris.contract.utils; package com.tencent.cloud.polaris.contract.utils;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; 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 com.tencent.cloud.polaris.contract.SwaggerContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.PathSelectors;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.google.common.base.Optional.fromNullable;
/** /**
* Util for package processing. * Util for package processing.
* *
@ -44,87 +35,15 @@ import static com.google.common.base.Optional.fromNullable;
*/ */
public final class PackageUtil { public final class PackageUtil {
/**
* splitter for property.
*/
public static final String SPLITTER = ",";
private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class); private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class);
private static final String SPLITTER = ",";
private PackageUtil() { private PackageUtil() {
} }
public static Predicate<RequestHandler> basePackage(String basePackage) {
return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false);
}
public static Optional<Class<?>> declaringClass(RequestHandler input) {
if (input == null) {
return Optional.absent();
}
return fromNullable(input.declaringClass());
}
public static Function<Class<?>, 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<Predicate<String>> getExcludePathPredicates(String excludePath) {
List<Predicate<String>> 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<Predicate<String>> getBasePathPredicates(String basePath) {
List<Predicate<String>> 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) { public static String scanPackage(String configBasePackage) {
String validScanPackage; String validScanPackage;
// Externally configured scan package // Externally configured scan package

@ -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());
}
}

@ -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);
}
}

@ -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);
}
}

@ -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<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<PatternsRequestCondition> other) {
if (other instanceof WebMvcPatternsRequestConditionWrapper && !this.equals(other)) {
return new WebMvcPatternsRequestConditionWrapper(
contextPath,
condition.combine(((WebMvcPatternsRequestConditionWrapper) other).condition));
}
return this;
}
@Override
public Set<String> 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();
}
}

@ -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<? extends Annotation> 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<RequestMethod> supportedMethods() {
return requestMapping.getMethodsCondition().getMethods();
}
@Override
public Set<MediaType> produces() {
return requestMapping.getProducesCondition().getProducibleMediaTypes();
}
@Override
public Set<MediaType> consumes() {
return requestMapping.getConsumesCondition().getConsumableMediaTypes();
}
@Override
public Set<NameValueExpression<String>> headers() {
return WebMvcNameValueExpressionWrapper.from(requestMapping.getHeadersCondition().getExpressions());
}
@Override
public Set<NameValueExpression<String>> params() {
return WebMvcNameValueExpressionWrapper.from(requestMapping.getParamsCondition().getExpressions());
}
@Override
public <T extends Annotation> Optional<T> findAnnotation(Class<T> annotation) {
return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation));
}
@Override
public RequestHandlerKey key() {
// polaris add start
Set<String> 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<ResolvedMethodParameter> getParameters() {
return methodResolver.methodParameters(handlerMethod);
}
@Override
public ResolvedType getReturnType() {
return methodResolver.methodReturnType(handlerMethod);
}
@Override
public <T extends Annotation> Optional<T> findControllerAnnotation(Class<T> 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();
}
}

@ -76,7 +76,7 @@
<polaris.version>1.15.0-SNAPSHOT</polaris.version> <polaris.version>1.15.0-SNAPSHOT</polaris.version>
<guava.version>32.0.1-jre</guava.version> <guava.version>32.0.1-jre</guava.version>
<logback.version>1.2.13</logback.version> <logback.version>1.2.13</logback.version>
<springfox.swagger2.version>3.0.0</springfox.swagger2.version> <springdoc.version>1.7.0</springdoc.version>
<io.swagger.version>1.5.24</io.swagger.version> <io.swagger.version>1.5.24</io.swagger.version>
<mocktio.version>4.5.1</mocktio.version> <mocktio.version>4.5.1</mocktio.version>
<byte-buddy.version>1.12.10</byte-buddy.version> <byte-buddy.version>1.12.10</byte-buddy.version>
@ -239,21 +239,15 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>org.springdoc</groupId>
<artifactId>springfox-boot-starter</artifactId> <artifactId>springdoc-openapi-ui</artifactId>
<version>${springfox.swagger2.version}</version> <version>${springdoc.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>org.springdoc</groupId>
<artifactId>swagger-models</artifactId> <artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>${io.swagger.version}</version> <version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${io.swagger.version}</version>
</dependency> </dependency>
<dependency> <dependency>

@ -14,7 +14,7 @@ spring:
contract: contract:
exposure: true exposure: true
report: report:
enabled: false enabled: true
stat: stat:
enabled: true enabled: true
port: 28083 port: 28083

@ -14,7 +14,7 @@ spring:
contract: contract:
exposure: true exposure: true
report: report:
enabled: false enabled: true
stat: stat:
enabled: true enabled: true
port: 28084 port: 28084

@ -17,7 +17,7 @@ spring:
contract: contract:
exposure: true exposure: true
report: report:
enabled: false enabled: true
circuitbreaker: circuitbreaker:
enabled: true enabled: true
stat: stat:

@ -21,7 +21,7 @@ spring:
contract: contract:
exposure: true exposure: true
report: report:
enabled: false enabled: true
stat: stat:
enabled: true enabled: true
port: 28081 port: 28081

Loading…
Cancel
Save