Skip to content

Commit

Permalink
Merge pull request #57 from SpringForAll/1.6.0
Browse files Browse the repository at this point in the history
1.6.0
  • Loading branch information
程序猿DD-翟永超 authored Feb 8, 2018
2 parents cd6d750 + 44b58d5 commit 7f68606
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 21 deletions.
86 changes: 80 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- 码云:https://gitee.com/didispace/spring-boot-starter-swagger
- 使用样例:https://github.com/dyc87112/swagger-starter-demo
- 我的博客:http://blog.didispace.com
- 我们社区:http://spring4all.com
- 我们社区:http://www.spring4all.com

**小工具一枚,欢迎使用和Star支持,如使用过程中碰到问题,可以提出Issue,我会尽力完善该Starter**

Expand All @@ -27,11 +27,13 @@
```xml
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.5.1.RELEASE</version>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
```

**注意:从`1.6.0`开始,我们按Spring Boot官方建议修改了artifactId为`swagger-spring-boot-starter`,1.6.0之前的版本不做修改,依然为使用`spring-boot-starter-swagger` !**

- 在应用主类中增加`@EnableSwagger2Doc`注解

```java
Expand Down Expand Up @@ -80,13 +82,24 @@ swagger.globalOperationParameters[1].description=some description two
swagger.globalOperationParameters[1].modelRef=string
swagger.globalOperationParameters[1].parameterType=body
swagger.globalOperationParameters[1].required=false

// 取消使用默认预定义的响应消息,并使用自定义响应消息
swagger.apply-default-response-messages=false
swagger.global-response-message.get[0].code=401
swagger.global-response-message.get[0].message=401get
swagger.global-response-message.get[1].code=500
swagger.global-response-message.get[1].message=500get
swagger.global-response-message.get[1].modelRef=ERROR
swagger.global-response-message.post[0].code=500
swagger.global-response-message.post[0].message=500post
swagger.global-response-message.post[0].modelRef=ERROR
```

## 配置说明

### 默认配置

```
```properties
- swagger.enabled=是否启用swagger,默认:true
- swagger.title=标题
- swagger.description=描述
Expand Down Expand Up @@ -142,7 +155,7 @@ swagger.exclude-path=/ops/**, /error

具体配置内容如下:

```
```properties
- swagger.docket.<name>.title=标题
- swagger.docket.<name>.description=描述
- swagger.docket.<name>.version=版本
Expand Down Expand Up @@ -190,7 +203,7 @@ swagger.docket.bbb.basePackage=com.yonghui

说明:默认配置与分组配置可以一起使用。在分组配置中没有配置的内容将使用默认配置替代,所以默认配置可以作为分组配置公共部分属性的配置。`swagger.docket.aaa.globalOperationParameters[0].name`会覆盖同名的全局配置。

### JSR-303校验注解支持
### JSR-303校验注解支持(1.5.0 + 支持)

支持对JSR-303校验注解的展示,如下图所示:

Expand All @@ -203,7 +216,68 @@ swagger.docket.bbb.basePackage=com.yonghui
- `@Size`
- `@Pattern`

### 自定义全局响应消息配置(1.6.0 + 支持)

支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE 全局响应消息配置,配置如下

```properties
// 取消使用默认预定义的响应消息,并使用自定义响应消息
swagger.apply-default-response-messages=false
swagger.global-response-message.get[0].code=401
swagger.global-response-message.get[0].message=401get
swagger.global-response-message.get[1].code=500
swagger.global-response-message.get[1].message=500get
swagger.global-response-message.get[1].modelRef=ERROR
swagger.global-response-message.post[0].code=500
swagger.global-response-message.post[0].message=500post
swagger.global-response-message.post[0].modelRef=ERROR
```

### UI功能配置(1.6.0 + 支持)

- 调试按钮的控制(try it out)

```properties
swagger.ui-config.submit-methods=get,delete
```

该参数值为提供调试按钮的HTTP请求类型,多个用,分割。

如果不想开启调试功能,只需要如下设置即可:

```properties
swagger.ui-config.submit-methods=
```

- 其他配置

```properties
# json编辑器
swagger.ui-config.json-editor=false
# 显示请求头
swagger.ui-config.show-request-headers=true
# 页面调试请求的超时时间
swagger.ui-config.request-timeout=5000
```

### ignoredParameterTypes配置(1.6.0 + 支持)

```properties
# 基础配置
swagger.ignored-parameter-types[0]=com.didispace.demo.User
swagger.ignored-parameter-types[1]=com.didispace.demo.Product

# 分组配置
swagger.docket.aaa.ignored-parameter-types[0]=com.didispace.demo.User
swagger.docket.aaa.ignored-parameter-types[1]=com.didispace.demo.Product
```

> 该参数作用:
> Q. Infinite loop when springfox tries to determine schema for objects with nested/complex constraints?
> A. If you have recursively defined objects, I would try and see if providing an alternate type might work or perhaps even ignoring the offending classes e.g. order using the docket. ignoredParameterTypes(Order.class). This is usually found in Hibernate domain objects that have bidirectional dependencies on other objects.
## 贡献者

- [程序猿DD-翟永超](https://github.com/dyc87112/)
- [小火](https://renlulu.github.io/)
- [泥瓦匠BYSocket](https://github.com/JeffLi1993)
9 changes: 7 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion>

<groupId>com.spring4all</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.5.1.RELEASE</version>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.6.0.RELEASE</version>

<name>spring-boot-starter-swagger</name>
<url>https://github.com/SpringForAll/spring-boot-starter-swagger</url>
Expand Down Expand Up @@ -84,6 +84,11 @@
<version>1.16.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
116 changes: 104 additions & 12 deletions src/main/java/com/spring4all/swagger/SwaggerAutoConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@
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.ConditionalOnBean;
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 org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.*;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.UiConfiguration;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -45,8 +47,22 @@ public SwaggerProperties swaggerProperties() {
return new SwaggerProperties();
}

@Bean
public UiConfiguration uiConfiguration(SwaggerProperties swaggerProperties) {
return new UiConfiguration(
swaggerProperties.getUiConfig().getValidatorUrl(),// url
swaggerProperties.getUiConfig().getDocExpansion(), // docExpansion => none | list
swaggerProperties.getUiConfig().getApiSorter(), // apiSorter => alpha
swaggerProperties.getUiConfig().getDefaultModelRendering(), // defaultModelRendering => schema
swaggerProperties.getUiConfig().getSubmitMethods().split(","),
swaggerProperties.getUiConfig().getJsonEditor(), // enableJsonEditor => true | false
swaggerProperties.getUiConfig().getShowRequestHeaders(), // showRequestHeaders => true | false
swaggerProperties.getUiConfig().getRequestTimeout()); // requestTimeout => in milliseconds, defaults to null (uses jquery xh timeout)
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(UiConfiguration.class)
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
Expand Down Expand Up @@ -82,20 +98,30 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
excludePath.add(PathSelectors.ant(path));
}

Docket docket = new Docket(DocumentationType.SWAGGER_2)
Docket docketForBuilder = new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost())
.apiInfo(apiInfo)
.globalOperationParameters(buildGlobalOperationParametersFromSwaggerProperties(
swaggerProperties.getGlobalOperationParameters()))
.select()
swaggerProperties.getGlobalOperationParameters()));

// 全局响应消息
if (!swaggerProperties.getApplyDefaultResponseMessages()) {
buildGlobalResponseMessage(swaggerProperties, docketForBuilder);
}

Docket docket = docketForBuilder.select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
.paths(
Predicates.and(
Predicates.not(Predicates.or(excludePath)),
Predicates.or(basePath)
)
)
.build();
).build();

/** ignoredParameterTypes **/
Class[] array = new Class[swaggerProperties.getIgnoredParameterTypes().size()];
Class[] ignoredParameterTypes = swaggerProperties.getIgnoredParameterTypes().toArray(array);
docket.ignoredParameterTypes(ignoredParameterTypes);

configurableBeanFactory.registerSingleton("defaultDocket", docket);
docketList.add(docket);
Expand Down Expand Up @@ -138,12 +164,18 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
excludePath.add(PathSelectors.ant(path));
}

Docket docket = new Docket(DocumentationType.SWAGGER_2)
Docket docketForBuilder = new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost())
.apiInfo(apiInfo)
.globalOperationParameters(assemblyGlobalOperationParameters(swaggerProperties.getGlobalOperationParameters(),
docketInfo.getGlobalOperationParameters()))
.groupName(groupName)
docketInfo.getGlobalOperationParameters()));

// 全局响应消息
if (!swaggerProperties.getApplyDefaultResponseMessages()) {
buildGlobalResponseMessage(swaggerProperties, docketForBuilder);
}

Docket docket = docketForBuilder.groupName(groupName)
.select()
.apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage()))
.paths(
Expand All @@ -154,17 +186,24 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
)
.build();

/** ignoredParameterTypes **/
Class[] array = new Class[docketInfo.getIgnoredParameterTypes().size()];
Class[] ignoredParameterTypes = docketInfo.getIgnoredParameterTypes().toArray(array);
docket.ignoredParameterTypes(ignoredParameterTypes);

configurableBeanFactory.registerSingleton(groupName, docket);
docketList.add(docket);
}
return docketList;
}


@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}


private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties(
List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) {
List<Parameter> parameters = Lists.newArrayList();
Expand Down Expand Up @@ -216,4 +255,57 @@ private List<Parameter> assemblyGlobalOperationParameters(
resultOperationParameters.addAll(docketOperationParameters);
return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters);
}

/**
* 设置全局响应消息
*
* @param swaggerProperties 支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE
* @param docketForBuilder
*/
private void buildGlobalResponseMessage(SwaggerProperties swaggerProperties, Docket docketForBuilder) {

SwaggerProperties.GlobalResponseMessage globalResponseMessages =
swaggerProperties.getGlobalResponseMessage();

// POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE 响应消息体
List<ResponseMessage> postResponseMessages = getResponseMessageList(globalResponseMessages.getPost());
List<ResponseMessage> getResponseMessages = getResponseMessageList(globalResponseMessages.getGet());
List<ResponseMessage> putResponseMessages = getResponseMessageList(globalResponseMessages.getPut());
List<ResponseMessage> patchResponseMessages = getResponseMessageList(globalResponseMessages.getPatch());
List<ResponseMessage> deleteResponseMessages = getResponseMessageList(globalResponseMessages.getDelete());
List<ResponseMessage> headResponseMessages = getResponseMessageList(globalResponseMessages.getHead());
List<ResponseMessage> optionsResponseMessages = getResponseMessageList(globalResponseMessages.getOptions());
List<ResponseMessage> trackResponseMessages = getResponseMessageList(globalResponseMessages.getTrace());

docketForBuilder.useDefaultResponseMessages(swaggerProperties.getApplyDefaultResponseMessages())
.globalResponseMessage(RequestMethod.POST, postResponseMessages)
.globalResponseMessage(RequestMethod.GET, getResponseMessages)
.globalResponseMessage(RequestMethod.PUT, putResponseMessages)
.globalResponseMessage(RequestMethod.PATCH, patchResponseMessages)
.globalResponseMessage(RequestMethod.DELETE, deleteResponseMessages)
.globalResponseMessage(RequestMethod.HEAD, headResponseMessages)
.globalResponseMessage(RequestMethod.OPTIONS, optionsResponseMessages)
.globalResponseMessage(RequestMethod.TRACE, trackResponseMessages);
}

/**
* 获取返回消息体列表
*
* @param globalResponseMessageBodyList
* @return
*/
private List<ResponseMessage> getResponseMessageList(List<SwaggerProperties.GlobalResponseMessageBody> globalResponseMessageBodyList) {
List<ResponseMessage> responseMessages = new ArrayList<>();
for (SwaggerProperties.GlobalResponseMessageBody globalResponseMessageBody : globalResponseMessageBodyList) {
ResponseMessageBuilder responseMessageBuilder = new ResponseMessageBuilder();
responseMessageBuilder.code(globalResponseMessageBody.getCode()).message(globalResponseMessageBody.getMessage());

if (!StringUtils.isEmpty(globalResponseMessageBody.getModelRef())) {
responseMessageBuilder.responseModel(new ModelRef(globalResponseMessageBody.getModelRef()));
}
responseMessages.add(responseMessageBuilder.build());
}

return responseMessages;
}
}
Loading

0 comments on commit 7f68606

Please sign in to comment.