|
|
@@ -1,7 +1,9 @@
|
|
|
package com.storlead.framework.web.config;
|
|
|
|
|
|
+import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
|
|
|
import com.storlead.framework.common.constant.DefContants;
|
|
|
-import io.swagger.annotations.ApiOperation;
|
|
|
+import org.springframework.beans.BeansException;
|
|
|
+import org.springframework.beans.factory.config.BeanPostProcessor;
|
|
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
|
|
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
|
|
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
|
|
@@ -13,53 +15,90 @@ import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandl
|
|
|
import org.springframework.context.annotation.Bean;
|
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
import org.springframework.core.env.Environment;
|
|
|
+import org.springframework.util.ReflectionUtils;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
|
+import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
|
|
import springfox.documentation.builders.ApiInfoBuilder;
|
|
|
-import springfox.documentation.builders.ParameterBuilder;
|
|
|
import springfox.documentation.builders.PathSelectors;
|
|
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
|
-import springfox.documentation.schema.ModelRef;
|
|
|
import springfox.documentation.service.*;
|
|
|
import springfox.documentation.spi.DocumentationType;
|
|
|
import springfox.documentation.spi.service.contexts.SecurityContext;
|
|
|
import springfox.documentation.spring.web.plugins.Docket;
|
|
|
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
|
+import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
|
|
|
+import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
|
|
|
|
|
|
+import java.lang.reflect.Field;
|
|
|
import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
- * @program: sp-sales-platform
|
|
|
- * @description:
|
|
|
- * @author: chenkq
|
|
|
- * @create: 2024-03-29 17:35
|
|
|
+ * Springfox 3 + Knife4j 3:统一扫描 com.storlead 下全部 Controller。
|
|
|
*/
|
|
|
-
|
|
|
@Configuration
|
|
|
+@EnableSwagger2
|
|
|
+@EnableKnife4j
|
|
|
public class Swagger2Config implements WebMvcConfigurer {
|
|
|
|
|
|
- // 显示swagger-ui.html文档展示页,还必须注入swagger资源:
|
|
|
-
|
|
|
@Override
|
|
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
|
- registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
|
|
|
- registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
|
|
|
- registry.addResourceHandler("/webjars/").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
|
|
+ registry.addResourceHandler("/swagger-ui.html")
|
|
|
+ .addResourceLocations("classpath:/META-INF/resources/");
|
|
|
+ registry.addResourceHandler("/doc.html")
|
|
|
+ .addResourceLocations("classpath:/META-INF/resources/");
|
|
|
+ registry.addResourceHandler("/webjars/**")
|
|
|
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
|
|
|
}
|
|
|
|
|
|
- //
|
|
|
- // swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
|
|
|
-
|
|
|
- // @return Docket
|
|
|
+ /**
|
|
|
+ * Spring Boot 2.6+ 与 Springfox 兼容:去掉使用 PathPatternParser 的 HandlerMapping。
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
|
|
|
+ return new BeanPostProcessor() {
|
|
|
+ @Override
|
|
|
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
|
|
+ if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
|
|
|
+ customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
|
|
|
+ }
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
|
|
+ List<T> copy = mappings.stream()
|
|
|
+ .filter(mapping -> mapping.getPatternParser() == null)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ mappings.clear();
|
|
|
+ mappings.addAll(copy);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
|
|
+ Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
|
|
+ if (field == null) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ ReflectionUtils.makeAccessible(field);
|
|
|
+ try {
|
|
|
+ return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
+ throw new IllegalStateException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
|
|
|
@Bean
|
|
|
- public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier
|
|
|
- , ServletEndpointsSupplier servletEndpointsSupplier
|
|
|
- , ControllerEndpointsSupplier controllerEndpointsSupplier
|
|
|
- , EndpointMediaTypes endpointMediaTypes
|
|
|
- , CorsEndpointProperties corsProperties
|
|
|
- , WebEndpointProperties webEndpointProperties
|
|
|
- , Environment environment) {
|
|
|
+ public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
|
|
|
+ ServletEndpointsSupplier servletEndpointsSupplier,
|
|
|
+ ControllerEndpointsSupplier controllerEndpointsSupplier,
|
|
|
+ EndpointMediaTypes endpointMediaTypes,
|
|
|
+ CorsEndpointProperties corsProperties,
|
|
|
+ WebEndpointProperties webEndpointProperties,
|
|
|
+ Environment environment) {
|
|
|
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
|
|
|
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
|
|
allEndpoints.addAll(webEndpoints);
|
|
|
@@ -67,72 +106,54 @@ public class Swagger2Config implements WebMvcConfigurer {
|
|
|
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
|
|
|
String basePath = webEndpointProperties.getBasePath();
|
|
|
EndpointMapping endpointMapping = new EndpointMapping(basePath);
|
|
|
- boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
|
|
|
- return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
|
|
|
- }
|
|
|
- private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
|
|
|
- return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
|
|
|
+ boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
|
|
|
+ return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
|
|
|
+ corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
|
|
|
+ shouldRegisterLinksMapping, null);
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- public Docket platformAdminApi() {
|
|
|
- return buildGroupedDocket("platform-admin", "/platform/admin/.*");
|
|
|
+ private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
|
|
|
+ String basePath) {
|
|
|
+ return webEndpointProperties.getDiscovery().isEnabled()
|
|
|
+ && (StringUtils.hasText(basePath)
|
|
|
+ || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 单一分组,扫描 com.storlead 包下全部接口(不限制 @ApiOperation,避免漏接口)。
|
|
|
+ */
|
|
|
@Bean
|
|
|
- public Docket tenantAccountApi() {
|
|
|
- return buildGroupedDocket("tenant-account", "/account/.*");
|
|
|
- }
|
|
|
-
|
|
|
- private Docket buildGroupedDocket(String groupName, String pathRegex) {
|
|
|
+ public Docket allApiDocket() {
|
|
|
return new Docket(DocumentationType.SWAGGER_2)
|
|
|
- .groupName(groupName)
|
|
|
+ .groupName("all")
|
|
|
.apiInfo(apiInfo())
|
|
|
.select()
|
|
|
.apis(RequestHandlerSelectors.basePackage("com.storlead"))
|
|
|
- .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
|
|
- .paths(PathSelectors.regex(pathRegex))
|
|
|
+ .paths(PathSelectors.any())
|
|
|
.build()
|
|
|
- .securityContexts(Arrays.asList(securityContext()))
|
|
|
- .securitySchemes(Arrays.asList(new ApiKey("token", "token", io.swagger.v3.oas.models.security.SecurityScheme.In.HEADER.name())));
|
|
|
+ .securityContexts(Collections.singletonList(securityContext()))
|
|
|
+ .securitySchemes(Collections.singletonList(new ApiKey("token", DefContants.ACCESS_TOKEN, "header")));
|
|
|
}
|
|
|
|
|
|
private SecurityContext securityContext() {
|
|
|
return SecurityContext.builder()
|
|
|
.securityReferences(defaultAuth())
|
|
|
- //.forPaths(PathSelectors.regex("/*.*"))
|
|
|
.build();
|
|
|
}
|
|
|
|
|
|
private List<SecurityReference> defaultAuth() {
|
|
|
- AuthorizationScope authorizationScope
|
|
|
- = new AuthorizationScope("global", "accessEverything");
|
|
|
- AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
|
|
- authorizationScopes[0] = authorizationScope;
|
|
|
- return Collections.singletonList(
|
|
|
- new SecurityReference("token", authorizationScopes));
|
|
|
- }
|
|
|
-
|
|
|
- @Bean
|
|
|
- SecurityScheme securityScheme() {
|
|
|
- return new ApiKey(DefContants.ACCESS_TOKEN, DefContants.ACCESS_TOKEN, "header");
|
|
|
- }
|
|
|
-
|
|
|
- private List<Parameter> setHeaderToken() {
|
|
|
- ParameterBuilder tokenPar = new ParameterBuilder();
|
|
|
- List<Parameter> pars = new ArrayList<>();
|
|
|
- tokenPar.name("token").description("token").modelRef(new ModelRef("string")).parameterType("header")
|
|
|
- .required(false).build();
|
|
|
- pars.add(tokenPar.build());
|
|
|
- return pars;
|
|
|
+ AuthorizationScope scope = new AuthorizationScope("global", "accessEverything");
|
|
|
+ return Collections.singletonList(new SecurityReference("token", new AuthorizationScope[]{scope}));
|
|
|
}
|
|
|
|
|
|
private ApiInfo apiInfo() {
|
|
|
- return new ApiInfoBuilder() // //大标题
|
|
|
- .title("领存CRM后台服务API接口文档") // 版本号 .version("1.0") //
|
|
|
- .termsOfServiceUrl("NO terms of service") // 描述 .description("后台API接口")
|
|
|
+ return new ApiInfoBuilder()
|
|
|
+ .title("领存CRM后台服务API接口文档")
|
|
|
+ .description("com.storlead 包下全部 REST 接口")
|
|
|
+ .version("1.0")
|
|
|
+ .termsOfServiceUrl("NO terms of service")
|
|
|
.license("The Apache License, Version 2.0")
|
|
|
- .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html").build();
|
|
|
+ .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
|
|
|
+ .build();
|
|
|
}
|
|
|
-
|
|
|
}
|