From ff02ae0b56de3d08d1c04c3334529780e84cdd2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E5=AD=90=E9=BE=99?= <14096380+qwe963852@user.noreply.gitee.com> Date: Sun, 29 Sep 2024 10:12:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9Eswagger2=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E8=81=9A=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cloud-common/cloud-common-core/pom.xml | 6 + cloud-common/cloud-common-swagger/pom.xml | 38 +++ .../annotation/EnableCustomSwagger2.java | 10 + .../config/SwaggerAutoConfiguration.java | 117 +++++++ .../config/SwaggerBeanPostProcessor.java | 46 +++ .../swagger/config/SwaggerProperties.java | 303 ++++++++++++++++++ .../config/SwaggerWebConfiguration.java | 19 ++ cloud-common/pom.xml | 1 + 8 files changed, 540 insertions(+) create mode 100644 cloud-common/cloud-common-swagger/pom.xml create mode 100644 cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/annotation/EnableCustomSwagger2.java create mode 100644 cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerAutoConfiguration.java create mode 100644 cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerBeanPostProcessor.java create mode 100644 cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerProperties.java create mode 100644 cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerWebConfiguration.java diff --git a/cloud-common/cloud-common-core/pom.xml b/cloud-common/cloud-common-core/pom.xml index 57cf128..7cd55ff 100644 --- a/cloud-common/cloud-common-core/pom.xml +++ b/cloud-common/cloud-common-core/pom.xml @@ -17,6 +17,12 @@ + + + io.swagger + swagger-annotations + + org.springframework.cloud diff --git a/cloud-common/cloud-common-swagger/pom.xml b/cloud-common/cloud-common-swagger/pom.xml new file mode 100644 index 0000000..8d832cc --- /dev/null +++ b/cloud-common/cloud-common-swagger/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + com.muyu + cloud-server + 3.6.3 + ../../pom.xml + + + com.muyu + cloud-common-swagger + + cloud-common-swagger swagger2文档聚合 + + + 17 + 17 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.springfox + springfox-swagger2 + ${swagger.fox.version} + + + + diff --git a/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/annotation/EnableCustomSwagger2.java b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/annotation/EnableCustomSwagger2.java new file mode 100644 index 0000000..0d36ba9 --- /dev/null +++ b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/annotation/EnableCustomSwagger2.java @@ -0,0 +1,10 @@ +package com.muyu.common.swagger.annotation; + +/** + * @author 袁子龙 + * @package:com.muyu.common.swagger.annotation + * @name:EnableCustomSwagger2 + * @date:2024/9/29 10:01 + */ +public @interface EnableCustomSwagger2 { +} diff --git a/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerAutoConfiguration.java b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerAutoConfiguration.java new file mode 100644 index 0000000..42846b0 --- /dev/null +++ b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerAutoConfiguration.java @@ -0,0 +1,117 @@ +package com.muyu.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; + +/** + * @author 袁子龙 + * @package:com.muyu.common.swagger.config + * @name:SwaggerAutoConfiguration + * @date:2024/9/29 10:07 + */ +@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/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerBeanPostProcessor.java b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerBeanPostProcessor.java new file mode 100644 index 0000000..be3d265 --- /dev/null +++ b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerBeanPostProcessor.java @@ -0,0 +1,46 @@ +package com.muyu.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; + +/** + * @author 袁子龙 + * @package:com.muyu.common.swagger.config + * @name:SwaggerBeanPostProcessor + * @date:2024/9/29 10:07 + */ +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/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerProperties.java b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerProperties.java new file mode 100644 index 0000000..9be178f --- /dev/null +++ b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerProperties.java @@ -0,0 +1,303 @@ +package com.muyu.common.swagger.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author 袁子龙 + * @package:com.muyu.common.swagger.config + * @name:SwaggerProperties + * @date:2024/9/29 10:08 + */ +@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/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerWebConfiguration.java b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerWebConfiguration.java new file mode 100644 index 0000000..a790836 --- /dev/null +++ b/cloud-common/cloud-common-swagger/src/main/java/com/muyu/common/swagger/config/SwaggerWebConfiguration.java @@ -0,0 +1,19 @@ +package com.muyu.common.swagger.config; + +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author 袁子龙 + * @package:com.muyu.common.swagger.config + * @name:SwaggerWebConfiguration + * @date:2024/9/29 10:08 + */ +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/cloud-common/pom.xml b/cloud-common/pom.xml index a7a40be..1454b00 100644 --- a/cloud-common/pom.xml +++ b/cloud-common/pom.xml @@ -21,6 +21,7 @@ cloud-common-xxl cloud-common-rabbit cloud-common-saas + cloud-common-swagger cloud-common