diff --git a/.gitignore b/.gitignore index 6143e53..9ff7aa7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +.idea/ +spring-boot-starter-swagger.iml +target/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a322442 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: java + +jdk: + - oraclejdk8 + +install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true diff --git a/README.md b/README.md index ac3eded..75a812d 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,16 @@ swagger.contact.email=dyc87112@qq.com swagger.base-package=com.didispace swagger.base-path=/** swagger.exclude-path=/error, /ops/** +swagger.globalOperationParameters[0].name=name one +swagger.globalOperationParameters[0].description=some description one +swagger.globalOperationParameters[0].modelRef=string +swagger.globalOperationParameters[0].parameterType=header +swagger.globalOperationParameters[0].required=true +swagger.globalOperationParameters[1].name=name two +swagger.globalOperationParameters[1].description=some description two +swagger.globalOperationParameters[1].modelRef=string +swagger.globalOperationParameters[1].parameterType=body +swagger.globalOperationParameters[1].required=false ``` ## 配置说明 @@ -85,8 +95,14 @@ swagger.exclude-path=/error, /ops/** - swagger.base-path=需要处理的基础URL规则,默认:/** - swagger.exclude-path=需要排除的URL规则,默认:空 - swagger.host=文档的host信息,默认:空 +- swagger.globalOperationParameters[0].name=参数名 +- swagger.globalOperationParameters[0].description=描述信息 +- swagger.globalOperationParameters[0].modelRef=指定参数类型 +- swagger.globalOperationParameters[0].parameterType=指定参数存放位置,可选header,query,path,body.form +- swagger.globalOperationParameters[0].required=指定参数是否必传,true,false ``` + > host属性从1.3.0.RELEASE开始支持 ### Path规则说明 @@ -129,10 +145,19 @@ swagger.exclude-path=/ops/**, /error - swagger.docket..base-package=swagger扫描的基础包,默认:全扫描 - swagger.docket..base-path=需要处理的基础URL规则,默认:/** - swagger.docket..exclude-path=需要排除的URL规则,默认:空 +- swagger.docket..name=参数名 +- swagger.docket..modelRef=指定参数类型 +- swagger.docket..parameterType=指定参数存放位置,可选header,query,path,body.form +- swagger.docket..required=true=指定参数是否必传,true,false +- swagger.docket..globalOperationParameters[0].name=参数名 +- swagger.docket..globalOperationParameters[0].description=描述信息 +- swagger.docket..globalOperationParameters[0].modelRef=指定参数存放位置,可选header,query,path,body.form +- swagger.docket..globalOperationParameters[0].parameterType=指定参数是否必传,true,false ``` 说明:``为swagger文档的分组名称,同一个项目中可以配置多个分组,用来划分不同的API文档。 + **分组配置示例** ```properties @@ -144,13 +169,21 @@ swagger.docket.aaa.contact.name=zhaiyongchao swagger.docket.aaa.contact.url=http://spring4all.com/ swagger.docket.aaa.contact.email=didi@potatomato.club swagger.docket.aaa.excludePath=/ops/** +swagger.docket.aaa.globalOperationParameters[0].name=name three +swagger.docket.aaa.globalOperationParameters[0].description=some description three override +swagger.docket.aaa.globalOperationParameters[0].modelRef=string +swagger.docket.aaa.globalOperationParameters[0].parameterType=header swagger.docket.bbb.title=group-bbb swagger.docket.bbb.basePackage=com.yonghui + + ``` 说明:默认配置与分组配置可以一起使用。在分组配置中没有配置的内容将使用默认配置替代,所以默认配置可以作为分组配置公共部分属性的配置。 +`swagger.docket.aaa.globalOperationParameters[0].name` 会覆盖同名的全局配置 + ### JSR-303校验注解支持 支持对JSR-303校验注解的展示,如下图所示: diff --git a/src/main/java/com/didispace/swagger/SwaggerAutoConfiguration.java b/src/main/java/com/didispace/swagger/SwaggerAutoConfiguration.java index d1689be..7403703 100644 --- a/src/main/java/com/didispace/swagger/SwaggerAutoConfiguration.java +++ b/src/main/java/com/didispace/swagger/SwaggerAutoConfiguration.java @@ -2,6 +2,7 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.Lists; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -10,16 +11,21 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.Contact; +import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * @author 翟永超 @@ -43,7 +49,7 @@ public List createRestApi(SwaggerProperties swaggerProperties) { ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; // 没有分组 - if(swaggerProperties.getDocket().size() == 0) { + if (swaggerProperties.getDocket().size() == 0) { ApiInfo apiInfo = new ApiInfoBuilder() .title(swaggerProperties.getTitle()) .description(swaggerProperties.getDescription()) @@ -58,23 +64,26 @@ public List createRestApi(SwaggerProperties swaggerProperties) { // base-path处理 // 当没有配置任何path的时候,解析/** - if(swaggerProperties.getBasePath().isEmpty()) { + if (swaggerProperties.getBasePath().isEmpty()) { swaggerProperties.getBasePath().add("/**"); } List> basePath = new ArrayList(); - for(String path : swaggerProperties.getBasePath()) { + for (String path : swaggerProperties.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List> excludePath = new ArrayList(); - for(String path : swaggerProperties.getExcludePath()) { + for (String path : swaggerProperties.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } + Docket docket = new Docket(DocumentationType.SWAGGER_2) .host(swaggerProperties.getHost()) .apiInfo(apiInfo) + .globalOperationParameters(buildGlobalOperationParametersFromSwaggerProperties( + swaggerProperties.getGlobalOperationParameters())) .select() .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) .paths( @@ -91,7 +100,7 @@ public List createRestApi(SwaggerProperties swaggerProperties) { // 分组创建 List docketList = new LinkedList<>(); - for(String groupName : swaggerProperties.getDocket().keySet()) { + for (String groupName : swaggerProperties.getDocket().keySet()) { SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName); ApiInfo apiInfo = new ApiInfoBuilder() @@ -102,9 +111,9 @@ public List createRestApi(SwaggerProperties swaggerProperties) { .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() + 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()) @@ -112,23 +121,25 @@ public List createRestApi(SwaggerProperties swaggerProperties) { // base-path处理 // 当没有配置任何path的时候,解析/** - if(docketInfo.getBasePath().isEmpty()) { + if (docketInfo.getBasePath().isEmpty()) { docketInfo.getBasePath().add("/**"); } List> basePath = new ArrayList(); - for(String path : docketInfo.getBasePath()) { + for (String path : docketInfo.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List> excludePath = new ArrayList(); - for(String path : docketInfo.getExcludePath()) { + 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())) @@ -150,4 +161,49 @@ public List createRestApi(SwaggerProperties swaggerProperties) { public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } + + private List buildGlobalOperationParametersFromSwaggerProperties( + List globalOperationParameters) { + List parameters = Lists.newArrayList(); + 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 (docketOperationParameters == null || docketOperationParameters.isEmpty()) { + return buildGlobalOperationParametersFromSwaggerProperties(globalOperationParameters); + } + + Set docketNames = docketOperationParameters.stream() + .map(SwaggerProperties.GlobalOperationParameter::getName) + .collect(Collectors.toSet()); + + List resultOperationParameters = Lists.newArrayList(); + + for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) { + if (!docketNames.contains(parameter.getName())) { + resultOperationParameters.add(parameter); + } + } + resultOperationParameters.addAll(docketOperationParameters); + return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters); + } } diff --git a/src/main/java/com/didispace/swagger/SwaggerProperties.java b/src/main/java/com/didispace/swagger/SwaggerProperties.java index cafc22d..4511360 100644 --- a/src/main/java/com/didispace/swagger/SwaggerProperties.java +++ b/src/main/java/com/didispace/swagger/SwaggerProperties.java @@ -3,6 +3,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.boot.context.properties.ConfigurationProperties; +import springfox.documentation.schema.ModelRef; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -47,6 +48,30 @@ public class SwaggerProperties { /**host信息**/ private String host = ""; + /**全局参数配置**/ + private List globalOperationParameters; + + + @Data + @NoArgsConstructor + public static class GlobalOperationParameter{ + /**参数名**/ + private String name; + + /**描述信息**/ + private String description; + + /**指定参数类型**/ + private String modelRef; + + /**参数放在哪个地方:header,query,path,body.form**/ + private String parameterType; + + /**参数是否必须传**/ + private String required; + + } + @Data @NoArgsConstructor public static class DocketInfo { @@ -74,6 +99,8 @@ public static class DocketInfo { /**在basePath基础上需要排除的url规则**/ private List excludePath = new ArrayList<>(); + private List globalOperationParameters; + } @Data