package com.central.common.swagger2; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; 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.ApiInfo; import springfox.documentation.service.ApiKey; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.Contact; import springfox.documentation.service.Parameter; import springfox.documentation.service.SecurityReference; 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 java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; /** * @author zlt * @date 2018/11/18 9:22 *

* Blog: https://zlt2000.gitee.io * Github: https://github.com/zlt2000 */ @Configuration @EnableSwagger2 @EnableKnife4j @Import(BeanValidatorPluginsConfiguration.class) public class SwaggerAutoConfiguration implements BeanFactoryAware { private static final String AUTH_KEY = "Authorization"; private BeanFactory beanFactory; @Bean @ConditionalOnMissingBean public SwaggerProperties swaggerProperties() { return new SwaggerProperties(); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty(name = "zlt.swagger.enabled", matchIfMissing = true) public List createRestApi(SwaggerProperties swaggerProperties) { ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; List docketList = new LinkedList<>(); // 没有分组 if (swaggerProperties.getDocket().size() == 0) { final Docket docket = createDocket(swaggerProperties); configurableBeanFactory.registerSingleton("defaultDocket", docket); docketList.add(docket); return docketList; } // 分组创建 for (String groupName : swaggerProperties.getDocket().keySet()) { SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName); ApiInfo apiInfo = new ApiInfoBuilder() .title(docketInfo.getTitle().isEmpty() ? swaggerProperties.getTitle() : docketInfo.getTitle()) .description(docketInfo.getDescription().isEmpty() ? swaggerProperties.getDescription() : docketInfo.getDescription()) .version(docketInfo.getVersion().isEmpty() ? swaggerProperties.getVersion() : docketInfo.getVersion()) .license(docketInfo.getLicense().isEmpty() ? swaggerProperties.getLicense() : docketInfo.getLicense()) .licenseUrl(docketInfo.getLicenseUrl().isEmpty() ? swaggerProperties.getLicenseUrl() : docketInfo.getLicenseUrl()) .contact( new Contact( docketInfo.getContact().getName().isEmpty() ? swaggerProperties.getContact().getName() : docketInfo.getContact().getName(), docketInfo.getContact().getUrl().isEmpty() ? swaggerProperties.getContact().getUrl() : docketInfo.getContact().getUrl(), docketInfo.getContact().getEmail().isEmpty() ? swaggerProperties.getContact().getEmail() : docketInfo.getContact().getEmail() ) ) .termsOfServiceUrl(docketInfo.getTermsOfServiceUrl().isEmpty() ? swaggerProperties.getTermsOfServiceUrl() : docketInfo.getTermsOfServiceUrl()) .build(); // base-path处理 // 当没有配置任何path的时候,解析/** if (docketInfo.getBasePath().isEmpty()) { docketInfo.getBasePath().add("/**"); } List> basePath = new ArrayList<>(docketInfo.getBasePath().size()); for (String path : docketInfo.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List> excludePath = new ArrayList<>(docketInfo.getExcludePath().size()); for (String path : docketInfo.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } Docket docket = new Docket(DocumentationType.SWAGGER_2) .host(swaggerProperties.getHost()) .apiInfo(apiInfo) .globalOperationParameters(assemblyGlobalOperationParameters(swaggerProperties.getGlobalOperationParameters(), docketInfo.getGlobalOperationParameters())) .groupName(groupName) .select() .apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage())) .paths( Predicates.and( Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath) ) ) .build() .securitySchemes(securitySchemes()) .securityContexts(securityContexts()); configurableBeanFactory.registerSingleton(groupName, docket); docketList.add(docket); } return docketList; } /** * 创建 Docket对象 * * @param swaggerProperties swagger配置 * @return Docket */ private Docket createDocket(final SwaggerProperties swaggerProperties) { ApiInfo apiInfo = new ApiInfoBuilder() .title(swaggerProperties.getTitle()) .description(swaggerProperties.getDescription()) .version(swaggerProperties.getVersion()) .license(swaggerProperties.getLicense()) .licenseUrl(swaggerProperties.getLicenseUrl()) .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()) .build(); // base-path处理 // 当没有配置任何path的时候,解析/** if (swaggerProperties.getBasePath().isEmpty()) { swaggerProperties.getBasePath().add("/**"); } List> basePath = new ArrayList<>(); for (String path : swaggerProperties.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List> excludePath = new ArrayList<>(); for (String path : swaggerProperties.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } return new Docket(DocumentationType.SWAGGER_2) .host(swaggerProperties.getHost()) .apiInfo(apiInfo) .globalOperationParameters(buildGlobalOperationParametersFromSwaggerProperties( swaggerProperties.getGlobalOperationParameters())) .select() .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) .paths( Predicates.and( Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath) ) ) .build() .securitySchemes(securitySchemes()) .securityContexts(securityContexts()); } @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } private List securityContexts() { List contexts = new ArrayList<>(1); SecurityContext securityContext = SecurityContext.builder() .securityReferences(defaultAuth()) //.forPaths(PathSelectors.regex("^(?!auth).*$")) .build(); contexts.add(securityContext); return contexts; } private List defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; List references = new ArrayList<>(1); references.add(new SecurityReference(AUTH_KEY, authorizationScopes)); return references; } private List securitySchemes() { List apiKeys = new ArrayList<>(1); ApiKey apiKey = new ApiKey(AUTH_KEY, AUTH_KEY, "header"); apiKeys.add(apiKey); return apiKeys; } private List buildGlobalOperationParametersFromSwaggerProperties( List globalOperationParameters) { List parameters = Lists.newArrayList(); if (Objects.isNull(globalOperationParameters)) { return parameters; } for (SwaggerProperties.GlobalOperationParameter globalOperationParameter : globalOperationParameters) { parameters.add(new ParameterBuilder() .name(globalOperationParameter.getName()) .description(globalOperationParameter.getDescription()) .modelRef(new ModelRef(globalOperationParameter.getModelRef())) .parameterType(globalOperationParameter.getParameterType()) .required(Boolean.parseBoolean(globalOperationParameter.getRequired())) .build()); } return parameters; } /** * 局部参数按照name覆盖局部参数 * * @param globalOperationParameters * @param docketOperationParameters * @return */ private List assemblyGlobalOperationParameters( List globalOperationParameters, List docketOperationParameters) { if (Objects.isNull(docketOperationParameters) || docketOperationParameters.isEmpty()) { return buildGlobalOperationParametersFromSwaggerProperties(globalOperationParameters); } Set docketNames = docketOperationParameters.stream() .map(SwaggerProperties.GlobalOperationParameter::getName) .collect(Collectors.toSet()); List resultOperationParameters = Lists.newArrayList(); if (Objects.nonNull(globalOperationParameters)) { for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) { if (!docketNames.contains(parameter.getName())) { resultOperationParameters.add(parameter); } } } resultOperationParameters.addAll(docketOperationParameters); return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters); } }