Skip to content

1.4.0 #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
language: java

jdk:
- oraclejdk8

install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<dependency>
<groupId>com.didispace</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.3.0.RELEASE</version>
<version>1.4.0.RELEASE</version>
</dependency>
```

Expand All @@ -53,9 +53,11 @@ public class Bootstrap {
## 配置示例

```properties
swagger.enabled=true

swagger.title=spring-boot-starter-swagger
swagger.description=Starter for swagger 2.x
swagger.version=1.3.0.RELEASE
swagger.version=1.4.0.RELEASE
swagger.license=Apache License, Version 2.0
swagger.licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.html
swagger.termsOfServiceUrl=https://github.com/dyc87112/spring-boot-starter-swagger
Expand All @@ -65,13 +67,25 @@ 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
```

## 配置说明

### 默认配置

```
- swagger.enabled=是否启用swagger,默认:true
- swagger.title=标题
- swagger.description=描述
- swagger.version=版本
Expand All @@ -85,9 +99,19 @@ 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开始支持

> `1.3.0.RELEASE`新增:`swagger.host`属性,同时也支持指定docket的配置
>
> `1.4.0.RELEASE`新增:
> - `swagger.enabled`:用于开关swagger的配置
> - `swagger.globalOperationParameters`:用于设置全局的参数,比如:header部分的accessToken等。该参数支持指定docket的配置。

### Path规则说明

Expand Down Expand Up @@ -129,10 +153,19 @@ swagger.exclude-path=/ops/**, /error
- swagger.docket.<name>.base-package=swagger扫描的基础包,默认:全扫描
- swagger.docket.<name>.base-path=需要处理的基础URL规则,默认:/**
- swagger.docket.<name>.exclude-path=需要排除的URL规则,默认:空
- swagger.docket.<name>.name=参数名
- swagger.docket.<name>.modelRef=指定参数类型
- swagger.docket.<name>.parameterType=指定参数存放位置,可选header,query,path,body.form
- swagger.docket.<name>.required=true=指定参数是否必传,true,false
- swagger.docket.<name>.globalOperationParameters[0].name=参数名
- swagger.docket.<name>.globalOperationParameters[0].description=描述信息
- swagger.docket.<name>.globalOperationParameters[0].modelRef=指定参数存放位置,可选header,query,path,body.form
- swagger.docket.<name>.globalOperationParameters[0].parameterType=指定参数是否必传,true,false
```

说明:`<name>`为swagger文档的分组名称,同一个项目中可以配置多个分组,用来划分不同的API文档。


**分组配置示例**

```properties
Expand All @@ -144,12 +177,16 @@ 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校验注解支持

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.didispace</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.3.0.RELEASE</version>
<version>1.4.0.RELEASE</version>

<name>spring-boot-starter-swagger</name>
<url>https://github.com/dyc87112/spring-boot-starter-swagger</url>
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/com/didispace/swagger/EnableSwagger2Doc.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.didispace.swagger;

import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.lang.annotation.*;

Expand All @@ -15,8 +13,7 @@
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableSwagger2
@Import({SwaggerAutoConfiguration.class, BeanValidatorPluginsConfiguration.class})
@Import({SwaggerAutoConfiguration.class})
public @interface EnableSwagger2Doc {


Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/didispace/swagger/Swagger2Configuration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.didispace.swagger;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration;

/**
* @author 翟永超
* Create Date: 2017/9/7.
* My blog: http://blog.didispace.com
*/
@Configuration
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@Import({
Swagger2DocumentationConfiguration.class,
BeanValidatorPluginsConfiguration.class
})
public class Swagger2Configuration {
}
86 changes: 74 additions & 12 deletions src/main/java/com/didispace/swagger/SwaggerAutoConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,42 @@

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;
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.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 翟永超
* Create date :2017/8/7.
* Create date:2017/8/7.
* My blog: http://blog.didispace.com
*/
@Configuration
@Import({
Swagger2Configuration.class
})
public class SwaggerAutoConfiguration implements BeanFactoryAware {

private BeanFactory beanFactory;
Expand All @@ -39,11 +50,12 @@ public SwaggerProperties swaggerProperties() {

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public List<Docket> 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())
Expand All @@ -58,23 +70,26 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {

// base-path处理
// 当没有配置任何path的时候,解析/**
if(swaggerProperties.getBasePath().isEmpty()) {
if (swaggerProperties.getBasePath().isEmpty()) {
swaggerProperties.getBasePath().add("/**");
}
List<Predicate<String>> basePath = new ArrayList();
for(String path : swaggerProperties.getBasePath()) {
for (String path : swaggerProperties.getBasePath()) {
basePath.add(PathSelectors.ant(path));
}

// exclude-path处理
List<Predicate<String>> 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(
Expand All @@ -91,7 +106,7 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {

// 分组创建
List<Docket> 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()
Expand All @@ -102,33 +117,35 @@ public List<Docket> 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())
.build();

// base-path处理
// 当没有配置任何path的时候,解析/**
if(docketInfo.getBasePath().isEmpty()) {
if (docketInfo.getBasePath().isEmpty()) {
docketInfo.getBasePath().add("/**");
}
List<Predicate<String>> basePath = new ArrayList();
for(String path : docketInfo.getBasePath()) {
for (String path : docketInfo.getBasePath()) {
basePath.add(PathSelectors.ant(path));
}

// exclude-path处理
List<Predicate<String>> 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()))
Expand All @@ -150,4 +167,49 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}

private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties(
List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) {
List<Parameter> 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<Parameter> assemblyGlobalOperationParameters(
List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters,
List<SwaggerProperties.GlobalOperationParameter> docketOperationParameters) {

if (docketOperationParameters == null || docketOperationParameters.isEmpty()) {
return buildGlobalOperationParametersFromSwaggerProperties(globalOperationParameters);
}

Set<String> docketNames = docketOperationParameters.stream()
.map(SwaggerProperties.GlobalOperationParameter::getName)
.collect(Collectors.toSet());

List<SwaggerProperties.GlobalOperationParameter> resultOperationParameters = Lists.newArrayList();

for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) {
if (!docketNames.contains(parameter.getName())) {
resultOperationParameters.add(parameter);
}
}
resultOperationParameters.addAll(docketOperationParameters);
return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters);
}
}
Loading