From 3b5164cf55f9904cd709d0b24d9b92c9423879b2 Mon Sep 17 00:00:00 2001 From: fst1996 <2411194573@qq.com> Date: Sat, 18 Nov 2023 14:45:28 +0800 Subject: [PATCH] =?UTF-8?q?god-common-swagger=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 46 +++ pom.xml | 51 +++ .../annotation/EnableCustomSwagger2.java | 15 + .../config/SwaggerAutoConfiguration.java | 111 +++++++ .../config/SwaggerBeanPostProcessor.java | 45 +++ .../swagger/config/SwaggerProperties.java | 296 ++++++++++++++++++ .../config/SwaggerWebConfiguration.java | 18 ++ ...ot.autoconfigure.AutoConfiguration.imports | 3 + 8 files changed, 585 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/god/common/swagger/annotation/EnableCustomSwagger2.java create mode 100644 src/main/java/com/god/common/swagger/config/SwaggerAutoConfiguration.java create mode 100644 src/main/java/com/god/common/swagger/config/SwaggerBeanPostProcessor.java create mode 100644 src/main/java/com/god/common/swagger/config/SwaggerProperties.java create mode 100644 src/main/java/com/god/common/swagger/config/SwaggerWebConfiguration.java create mode 100644 src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09bdfea --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ac73e91 --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + + com.god + god-common + 3.6.3 + + 4.0.0 + + god-common-swagger + 3.6.3 + + + god-common-swagger系统接口 + + + + + menghang-public + 梦航-public + http://10.100.1.6:8081/repository/maven-public/ + + + + + + menghang-releases + 梦航-releases + http://10.100.1.6:8081/repository/maven-releases/ + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.springfox + springfox-swagger2 + ${swagger.fox.version} + + + + diff --git a/src/main/java/com/god/common/swagger/annotation/EnableCustomSwagger2.java b/src/main/java/com/god/common/swagger/annotation/EnableCustomSwagger2.java new file mode 100644 index 0000000..78d1319 --- /dev/null +++ b/src/main/java/com/god/common/swagger/annotation/EnableCustomSwagger2.java @@ -0,0 +1,15 @@ +package com.god.common.swagger.annotation; + +import com.god.common.swagger.config.SwaggerAutoConfiguration; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Import({SwaggerAutoConfiguration.class}) +public @interface EnableCustomSwagger2 { + +} diff --git a/src/main/java/com/god/common/swagger/config/SwaggerAutoConfiguration.java b/src/main/java/com/god/common/swagger/config/SwaggerAutoConfiguration.java new file mode 100644 index 0000000..d6d6eb1 --- /dev/null +++ b/src/main/java/com/god/common/swagger/config/SwaggerAutoConfiguration.java @@ -0,0 +1,111 @@ +package com.god.common.swagger.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.*; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.ApiSelectorBuilder; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +@Configuration +@EnableSwagger2 +@EnableConfigurationProperties(SwaggerProperties.class) +@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true) +@Import({SwaggerBeanPostProcessor.class, SwaggerWebConfiguration.class}) +public class SwaggerAutoConfiguration { + /** + * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点 + */ + private static final List DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**"); + + private static final String BASE_PATH = "/**"; + + @Bean + public Docket api (SwaggerProperties swaggerProperties) { + // base-path处理 + if (swaggerProperties.getBasePath().isEmpty()) { + swaggerProperties.getBasePath().add(BASE_PATH); + } + // noinspection unchecked + List> basePath = new ArrayList>(); + swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path))); + + // exclude-path处理 + if (swaggerProperties.getExcludePath().isEmpty()) { + swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH); + } + + List> excludePath = new ArrayList<>(); + swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path))); + + ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost()) + .apiInfo(apiInfo(swaggerProperties)).select() + .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())); + + swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p))); + swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate())); + + return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/"); + } + + /** + * 安全模式,这里指定token通过Authorization头请求头传递 + */ + private List securitySchemes () { + List apiKeyList = new ArrayList(); + apiKeyList.add(new ApiKey("Authorization", "Authorization", "header")); + return apiKeyList; + } + + /** + * 安全上下文 + */ + private List securityContexts () { + List securityContexts = new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) + .build()); + return securityContexts; + } + + /** + * 默认的全局鉴权策略 + * + * @return + */ + private List defaultAuth () { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List securityReferences = new ArrayList<>(); + securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); + return securityReferences; + } + + private ApiInfo apiInfo (SwaggerProperties swaggerProperties) { + return new ApiInfoBuilder() + .title(swaggerProperties.getTitle()) + .description(swaggerProperties.getDescription()) + .license(swaggerProperties.getLicense()) + .licenseUrl(swaggerProperties.getLicenseUrl()) + .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()) + .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) + .version(swaggerProperties.getVersion()) + .build(); + } +} diff --git a/src/main/java/com/god/common/swagger/config/SwaggerBeanPostProcessor.java b/src/main/java/com/god/common/swagger/config/SwaggerBeanPostProcessor.java new file mode 100644 index 0000000..0f968f4 --- /dev/null +++ b/src/main/java/com/god/common/swagger/config/SwaggerBeanPostProcessor.java @@ -0,0 +1,45 @@ +package com.god.common.swagger.config; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; +import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider; +import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +/** + * swagger 在 springboot 2.6.x 不兼容问题的处理 + * + * @author god + */ +public class SwaggerBeanPostProcessor implements BeanPostProcessor { + @Override + public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { + if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) { + customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); + } + return bean; + } + + private void customizeSpringfoxHandlerMappings (List mappings) { + List copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null) + .collect(Collectors.toList()); + mappings.clear(); + mappings.addAll(copy); + } + + @SuppressWarnings("unchecked") + private List getHandlerMappings (Object bean) { + try { + Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); + field.setAccessible(true); + return (List) field.get(bean); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/src/main/java/com/god/common/swagger/config/SwaggerProperties.java b/src/main/java/com/god/common/swagger/config/SwaggerProperties.java new file mode 100644 index 0000000..2a49040 --- /dev/null +++ b/src/main/java/com/god/common/swagger/config/SwaggerProperties.java @@ -0,0 +1,296 @@ +package com.god.common.swagger.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.ArrayList; +import java.util.List; + +@ConfigurationProperties("swagger") +public class SwaggerProperties { + /** + * 是否开启swagger + */ + private Boolean enabled; + + /** + * swagger会解析的包路径 + **/ + private String basePackage = ""; + + /** + * swagger会解析的url规则 + **/ + private List basePath = new ArrayList<>(); + + /** + * 在basePath基础上需要排除的url规则 + **/ + private List excludePath = new ArrayList<>(); + + /** + * 标题 + **/ + private String title = ""; + + /** + * 描述 + **/ + private String description = ""; + + /** + * 版本 + **/ + private String version = ""; + + /** + * 许可证 + **/ + private String license = ""; + + /** + * 许可证URL + **/ + private String licenseUrl = ""; + + /** + * 服务条款URL + **/ + private String termsOfServiceUrl = ""; + + /** + * host信息 + **/ + private String host = ""; + + /** + * 联系人信息 + */ + private Contact contact = new Contact(); + + /** + * 全局统一鉴权配置 + **/ + private Authorization authorization = new Authorization(); + + public Boolean getEnabled () { + return enabled; + } + + public void setEnabled (Boolean enabled) { + this.enabled = enabled; + } + + public String getBasePackage () { + return basePackage; + } + + public void setBasePackage (String basePackage) { + this.basePackage = basePackage; + } + + public List getBasePath () { + return basePath; + } + + public void setBasePath (List basePath) { + this.basePath = basePath; + } + + public List getExcludePath () { + return excludePath; + } + + public void setExcludePath (List excludePath) { + this.excludePath = excludePath; + } + + public String getTitle () { + return title; + } + + public void setTitle (String title) { + this.title = title; + } + + public String getDescription () { + return description; + } + + public void setDescription (String description) { + this.description = description; + } + + public String getVersion () { + return version; + } + + public void setVersion (String version) { + this.version = version; + } + + public String getLicense () { + return license; + } + + public void setLicense (String license) { + this.license = license; + } + + public String getLicenseUrl () { + return licenseUrl; + } + + public void setLicenseUrl (String licenseUrl) { + this.licenseUrl = licenseUrl; + } + + public String getTermsOfServiceUrl () { + return termsOfServiceUrl; + } + + public void setTermsOfServiceUrl (String termsOfServiceUrl) { + this.termsOfServiceUrl = termsOfServiceUrl; + } + + public String getHost () { + return host; + } + + public void setHost (String host) { + this.host = host; + } + + public Contact getContact () { + return contact; + } + + public void setContact (Contact contact) { + this.contact = contact; + } + + public Authorization getAuthorization () { + return authorization; + } + + public void setAuthorization (Authorization authorization) { + this.authorization = authorization; + } + + public static class Contact { + /** + * 联系人 + **/ + private String name = ""; + /** + * 联系人url + **/ + private String url = ""; + /** + * 联系人email + **/ + private String email = ""; + + public String getName () { + return name; + } + + public void setName (String name) { + this.name = name; + } + + public String getUrl () { + return url; + } + + public void setUrl (String url) { + this.url = url; + } + + public String getEmail () { + return email; + } + + public void setEmail (String email) { + this.email = email; + } + } + + public static class Authorization { + /** + * 鉴权策略ID,需要和SecurityReferences ID保持一致 + */ + private String name = ""; + + /** + * 需要开启鉴权URL的正则 + */ + private String authRegex = "^.*$"; + + /** + * 鉴权作用域列表 + */ + private List authorizationScopeList = new ArrayList<>(); + + private List tokenUrlList = new ArrayList<>(); + + public String getName () { + return name; + } + + public void setName (String name) { + this.name = name; + } + + public String getAuthRegex () { + return authRegex; + } + + public void setAuthRegex (String authRegex) { + this.authRegex = authRegex; + } + + public List getAuthorizationScopeList () { + return authorizationScopeList; + } + + public void setAuthorizationScopeList (List authorizationScopeList) { + this.authorizationScopeList = authorizationScopeList; + } + + public List getTokenUrlList () { + return tokenUrlList; + } + + public void setTokenUrlList (List tokenUrlList) { + this.tokenUrlList = tokenUrlList; + } + } + + public static class AuthorizationScope { + /** + * 作用域名称 + */ + private String scope = ""; + + /** + * 作用域描述 + */ + private String description = ""; + + public String getScope () { + return scope; + } + + public void setScope (String scope) { + this.scope = scope; + } + + public String getDescription () { + return description; + } + + public void setDescription (String description) { + this.description = description; + } + } +} diff --git a/src/main/java/com/god/common/swagger/config/SwaggerWebConfiguration.java b/src/main/java/com/god/common/swagger/config/SwaggerWebConfiguration.java new file mode 100644 index 0000000..05a1088 --- /dev/null +++ b/src/main/java/com/god/common/swagger/config/SwaggerWebConfiguration.java @@ -0,0 +1,18 @@ +package com.god.common.swagger.config; + +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * swagger 资源映射路径 + * + * @author god + */ +public class SwaggerWebConfiguration implements WebMvcConfigurer { + @Override + public void addResourceHandlers (ResourceHandlerRegistry registry) { + /** swagger-ui 地址 */ + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/"); + } +} diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..749a52b --- /dev/null +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +# com.god.common.swagger.config.SwaggerAutoConfiguration +# com.god.common.swagger.config.SwaggerWebConfiguration +# com.god.common.swagger.config.SwaggerBeanPostProcessor