Skip to content

1.7.0 #69

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 7 commits into from
Mar 22, 2018
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
83 changes: 79 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# 简介

[![Build Status](https://travis-ci.org/dyc87112/spring-boot-starter-swagger.svg?branch=1.5.0)](https://travis-ci.org/dyc87112/spring-boot-starter-swagger)

该项目主要利用Spring Boot的自动化配置特性来实现快速的将swagger2引入spring boot应用来生成API文档,简化原生使用swagger2的整合代码。

- 源码地址
Expand All @@ -16,19 +14,21 @@
# 版本基础

- Spring Boot:1.5.x
- Swagger:2.7.x
- Swagger:2.8.x

# 如何使用

在该项目的帮助下,我们的Spring Boot可以轻松的引入swagger2,主需要做下面两个步骤:

- 在`pom.xml`中引入依赖:

> 当前最新版本 1.7.0.RELEASE

```xml
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.6.0.RELEASE</version>
<version>1.7.0.RELEASE</version>
</dependency>
```

Expand Down Expand Up @@ -254,8 +254,10 @@ 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
```
Expand All @@ -276,8 +278,81 @@ 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.

### Authorization 鉴权配置 (1.7.0 + 支持)

- 新增 Authorization 配置项

```properties
# 鉴权策略ID,对应 SecurityReferences ID
swagger.authorization.name=Authorization

# 鉴权传递的Header参数
swagger.authorization.key-name=token

# 需要开启鉴权URL的正则, 默认^.*$匹配所有URL
swagger.authorization.auth-regex=^.*$
```

备注:目前支持`ApiKey`鉴权模式,后续添加`Oauth2`和`BasicAuth`支持

**使用须知**

> 1. 默认已经在全局开启了`global`的SecurityReferences,无需配置任何参数就可以使用;
> 2. 全局鉴权的范围在可以通过以上参数`auth-regex`进行正则表达式匹配控制;
> 3. 除了全局开启外,还可以手动通过注解在RestController上进行定义鉴权,使用方式如下:

```java
// 其中的ID Authorization 即为配置项 swagger.authorization.name,详细请关注后面的配置代码
@ApiOperation(value = "Hello World", authorizations = {@Authorization(value = "Authorization")})
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String hello();
```

**关于如何配置实现鉴权,请关注以下code:**

```java
/**
* 配置基于 ApiKey 的鉴权对象
*
* @return
*/
private ApiKey apiKey() {
return new ApiKey(swaggerProperties().getAuthorization().getName(),
swaggerProperties().getAuthorization().getKeyName(),
ApiKeyVehicle.HEADER.getValue());
}

/**
* 配置默认的全局鉴权策略的开关,以及通过正则表达式进行匹配;默认 ^.*$ 匹配所有URL
* 其中 securityReferences 为配置启用的鉴权策略
*
* @return
*/
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
.build();
}

/**
* 配置默认的全局鉴权策略;其中返回的 SecurityReference 中,reference 即为ApiKey对象里面的name,保持一致才能开启全局鉴权
*
* @return
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Collections.singletonList(SecurityReference.builder()
.reference(swaggerProperties().getAuthorization().getName())
.scopes(authorizationScopes).build());
}
```

## 贡献者

- [程序猿DD-翟永超](https://github.com/dyc87112/)
- [小火](https://renlulu.github.io/)
- [泥瓦匠BYSocket](https://github.com/JeffLi1993)
- [LarryKoo-古拉里](https://github.com/gumutianqi)
9 changes: 5 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

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

<name>spring-boot-starter-swagger</name>
<url>https://github.com/SpringForAll/spring-boot-starter-swagger</url>
Expand Down Expand Up @@ -48,8 +48,9 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.java>1.8</version.java>
<version.swagger>2.7.0</version.swagger>
<version.spring-boot>1.5.6.RELEASE</version.spring-boot>
<version.swagger>2.8.0</version.swagger>
<version.spring-boot>1.5.10.RELEASE</version.spring-boot>
<version.lombok>1.16.18</version.lombok>
</properties>

<dependencies>
Expand Down Expand Up @@ -81,7 +82,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
<version>${version.lombok}</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down
137 changes: 93 additions & 44 deletions src/main/java/com/spring4all/swagger/SwaggerAutoConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand All @@ -17,17 +16,19 @@
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.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiKeyVehicle;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;

import java.util.*;
import java.util.stream.Collectors;

import static com.google.common.collect.Lists.newArrayList;

/**
* @author 翟永超
* Create date:2017/8/7.
Expand All @@ -49,15 +50,20 @@ public SwaggerProperties 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)
return UiConfigurationBuilder.builder()
.deepLinking(swaggerProperties.getUiConfig().getDeepLinking())
.defaultModelExpandDepth(swaggerProperties.getUiConfig().getDefaultModelExpandDepth())
.defaultModelRendering(swaggerProperties.getUiConfig().getDefaultModelRendering())
.defaultModelsExpandDepth(swaggerProperties.getUiConfig().getDefaultModelsExpandDepth())
.displayOperationId(swaggerProperties.getUiConfig().getDisplayOperationId())
.displayRequestDuration(swaggerProperties.getUiConfig().getDisplayRequestDuration())
.docExpansion(swaggerProperties.getUiConfig().getDocExpansion())
.maxDisplayedTags(swaggerProperties.getUiConfig().getMaxDisplayedTags())
.operationsSorter(swaggerProperties.getUiConfig().getOperationsSorter())
.showExtensions(swaggerProperties.getUiConfig().getShowExtensions())
.tagsSorter(swaggerProperties.getUiConfig().getTagsSorter())
.validatorUrl(swaggerProperties.getUiConfig().getValidatorUrl())
.build();
}

@Bean
Expand Down Expand Up @@ -93,14 +99,16 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
}

// exclude-path处理
List<Predicate<String>> excludePath = new ArrayList();
List<Predicate<String>> excludePath = new ArrayList<>();
for (String path : swaggerProperties.getExcludePath()) {
excludePath.add(PathSelectors.ant(path));
}

Docket docketForBuilder = new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost())
.apiInfo(apiInfo)
.securitySchemes(Collections.singletonList(apiKey()))
.securityContexts(Collections.singletonList(securityContext()))
.globalOperationParameters(buildGlobalOperationParametersFromSwaggerProperties(
swaggerProperties.getGlobalOperationParameters()));

Expand All @@ -118,9 +126,9 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
)
).build();

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

configurableBeanFactory.registerSingleton("defaultDocket", docket);
Expand Down Expand Up @@ -167,6 +175,8 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
Docket docketForBuilder = new Docket(DocumentationType.SWAGGER_2)
.host(swaggerProperties.getHost())
.apiInfo(apiInfo)
.securitySchemes(Collections.singletonList(apiKey()))
.securityContexts(Collections.singletonList(securityContext()))
.globalOperationParameters(assemblyGlobalOperationParameters(swaggerProperties.getGlobalOperationParameters(),
docketInfo.getGlobalOperationParameters()));

Expand All @@ -186,9 +196,9 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
)
.build();

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

configurableBeanFactory.registerSingleton(groupName, docket);
Expand All @@ -197,6 +207,44 @@ public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
return docketList;
}

/**
* 配置基于 ApiKey 的鉴权对象
*
* @return
*/
private ApiKey apiKey() {
return new ApiKey(swaggerProperties().getAuthorization().getName(),
swaggerProperties().getAuthorization().getKeyName(),
ApiKeyVehicle.HEADER.getValue());
}

/**
* 配置默认的全局鉴权策略的开关,以及通过正则表达式进行匹配;默认 ^.*$ 匹配所有URL
* 其中 securityReferences 为配置启用的鉴权策略
*
* @return
*/
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(swaggerProperties().getAuthorization().getAuthRegex()))
.build();
}

/**
* 配置默认的全局鉴权策略;其中返回的 SecurityReference 中,reference 即为ApiKey对象里面的name,保持一致才能开启全局鉴权
*
* @return
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Collections.singletonList(SecurityReference.builder()
.reference(swaggerProperties().getAuthorization().getName())
.scopes(authorizationScopes).build());
}


@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Expand All @@ -206,7 +254,7 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties(
List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) {
List<Parameter> parameters = Lists.newArrayList();
List<Parameter> parameters = newArrayList();

if (Objects.isNull(globalOperationParameters)) {
return parameters;
Expand Down Expand Up @@ -242,7 +290,7 @@ private List<Parameter> assemblyGlobalOperationParameters(
.map(SwaggerProperties.GlobalOperationParameter::getName)
.collect(Collectors.toSet());

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

if (Objects.nonNull(globalOperationParameters)) {
for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) {
Expand All @@ -259,42 +307,43 @@ private List<Parameter> assemblyGlobalOperationParameters(
/**
* 设置全局响应消息
*
* @param swaggerProperties 支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE
* @param docketForBuilder
* @param swaggerProperties swaggerProperties 支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE
* @param docketForBuilder swagger docket builder
*/
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());
/* 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);
.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
* @param globalResponseMessageBodyList 全局Code消息返回集合
* @return
*/
private List<ResponseMessage> getResponseMessageList(List<SwaggerProperties.GlobalResponseMessageBody> globalResponseMessageBodyList) {
private List<ResponseMessage> getResponseMessageList
(List<SwaggerProperties.GlobalResponseMessageBody> globalResponseMessageBodyList) {
List<ResponseMessage> responseMessages = new ArrayList<>();
for (SwaggerProperties.GlobalResponseMessageBody globalResponseMessageBody : globalResponseMessageBodyList) {
ResponseMessageBuilder responseMessageBuilder = new ResponseMessageBuilder();
Expand Down
Loading