随着前后端分离架构和微服务架构的流行,我们使用Spring Boot来构建RESTful API项目的场景越来越多。通常我们的一个RESTful API就有可能要服务于多个不同的开发人员或开发团队:IOS开发、Android开发、Web开发甚至其他的后端服务等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法就是创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题:
为了解决上面这样的问题,Swagger2应运而生,通过将Swagger2整合到我们的Spring Boot应用中,我们可以快速的组织出强大RESTful API文档,Swagger2大量的减少了我们创建文档的工作量,同时通过简单的Annotation将API说明内容整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明,进一步减少了我们维护文档的成本。
本文将要介绍的是一个GitHub上的一个开源项目spring-boot-starter-swagger
。该项目主要利用Spring Boot的自动化配置特性,对Swagger2进行了进一步的封装,更加简化了我们在Spring Boot应用中整合Swagger2的步骤。
Swagger2是一款业界比较流行的实现RESTful API的文档在线自动生成及RESTful API在线调试的工具。优点有:
Swagger2项目主页:https://swagger.io/
spring-boot-starter-swagger是一个GitHub上的一个开源项目,该项目主要利用Spring Boot的自动化配置特性来实现快速的将swagger2引入spring boot应用来生成API文档,简化原生使用swagger2的整合代码。
pom.xml
中引入依赖:<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
说明
1. 当前最新版本 1.9.0.RELEASE
;
2. 从1.6.0
版本开始,artifactId修改为swagger-spring-boot-starter
,1.6.0
之前的版本不做修改,依然为spring-boot-starter-swagger
;
@EnableSwagger2Doc
注解/**
*
* @ClassName: DemoApplication
* @Description: Demo应用启动类
* @author jjava
* @date 2019年10月31日 上午10:53:23
*
*/
@EnableSwagger2Doc
@SpringBootApplication
public class DemoApplication {
/**
* @Title main
* @Description 测试应用启动入口
* @author java
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
swagger:
base-package: swagger扫描的基础包,默认:全扫描
base-path: 需要处理的基础URL规则,默认:/**
contact:
email: 维护人email
name: 维护人
url: 维护人URL
description: 描述
enabled: 是否启用swagger,默认:true
exclude-path: 需要排除的URL规则,默认:空
globalOperationParameters:
- description: 描述信息
modelRef: 指定参数类型
name: 参数名
parameterType: 指定参数存放位置,可选header,query,path,body.form
required: 指定参数是否必传,true,false
host: 文档的host信息,默认:空
license: 许可证
licenseUrl: 许可证URL
termsOfServiceUrl: 服务条款URL
title: 标题
version: 版本
swagger:
apply-default-response-messages: false # 取消使用默认预定义的响应消息,并使用自定义响应消息
base-package: com.yuanx
base-path: /**
contact:
email: yx_222@163.com
name: YuanXu
url: https://blog.csdn.net/yx_222
description: Starter for swagger 2.x
enabled: true
exclude-path: /error, /ops/**
global-response-message:
get:
- code: 401
message: 页面不存在
- code: 500
message: 系统内部错误
modelRef: ERROR
post:
- code: 500
message: 系统内部错误
modelRef: ERROR
globalOperationParameters:
- description: some description one
modelRef: string
name: name one
parameterType: header
required: true
- description: some description two
modelRef: string
name: name two
parameterType: body
required: false
license: Apache License, Version 2.0
licenseUrl: https://www.apache.org/licenses/LICENSE-2.0.html
termsOfServiceUrl: https://github.com/dyc87112/spring-boot-starter-swagger
title: spring-boot-starter-swagger
version: 1.9.0.RELEASE
swagger.base-path
和swagger.exclude-path
使用ANT规则配置。
我们可以使用swagger.base-path
来指定所有需要生成文档的请求路径基础规则,然后再利用swagger.exclude-path
来剔除部分我们不需要的。
例如:
management:
context-path: /ops
swagger:
base-path: /**
exclude-path: /ops/**, /error
上面的设置将解析所有除了/ops/开始以及spring boot自带/error请求路径。
其中,exclude-path
可以配合management.context-path=/ops
设置的spring boot actuator的context-path来排除所有监控端点。
当我们一个项目的API非常多的时候,我们希望对API文档实现分组。从1.2.0.RELEASE开始,将支持分组配置功能,具体配置内容如下:
swagger:
docket:
<name>:
base-package: swagger扫描的基础包,默认:全扫描
base-path: 需要处理的基础URL规则,默认:/**
contact:
email: 维护人email
name: 维护人
url: 维护人URL
description: 描述
exclude-path: 需要排除的URL规则,默认:空
globalOperationParameters:
- description: 描述信息
modelRef: 指定参数存放位置,可选header,query,path,body.form
name: 参数名
parameterType: 指定参数是否必传,true,false
license: 许可证
licenseUrl: 许可证URL
modelRef: 指定参数类型
name: 参数名
parameterType: 指定参数存放位置,可选header,query,path,body.form
required: true=指定参数是否必传,true,false
termsOfServiceUrl: 服务条款URL
title: 标题
version: 版本
<name>
为swagger文档的分组名称,同一个项目中可以配置多个分组,用来划分不同的API文档。
swagger:
docket:
group-a:
contact:
email: yuan163.com
name: YuanXu
url: https://blog.csdn.net/yuan
description: Starter for swagger 2.x
excludePath: /ops/**, /error
globalOperationParameters:
- description: some description three override
modelRef: string
name: name three
parameterType: header
termsOfServiceUrl: https://gitee.com/didispace/spring-boot-starter-swagger
title: group-a
basePackage: com.hnu
version: 1.3.0.RELEASE
group-b:
title: group-b
basePackage: com.hnu
version: 1.3.0.RELEASE
默认配置与分组配置可以一起使用。在分组配置中没有配置的内容将使用默认配置替代,所以默认配置可以作为分组配置公共部分属性的配置。swagger.docket.aaa.globalOperationParameters[0].name
会覆盖同名的全局配置。
像每个接口都需要鉴权这种参数,可以在配置文件中统一定义,这样省去每个接口再写的麻烦,也能兼顾页面的测试。
swagger:
global-operation-parameters:
- name: TOKEN
description: 鉴权
modelRef: string
parameterType: header
required: true # 公共参数写成requierd, 对于不需要登录的接口随便写一个字符串即可
基础配置
swagger:
ignored-parameter-types:
- com.didispace.demo.User
- com.didispace.demo.Product
分组配置
swagger:
group-a:
ignored-parameter-types:
- com.didispace.demo.User
- com.didispace.demo.Product
支持 POST,GET,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE 全局响应消息配置,具体配置内容如下:
swagger:
apply-default-response-messages: false # 取消使用默认预定义的响应消息,并使用自定义响应消息
global-response-message:
get:
- code: 401
message: 401get
- code: 500
message: 500get
modelRef: ERROR
post:
- code: 500
message: 500post
modelRef: ERROR
调试按钮的控制(try it out)
swagger:
ui-config:
submit-methods: get,delete
该参数值为提供调试按钮的HTTP请求类型,多个用逗号分割,如果不想开启调试功能,只需要如下设置即可:
swagger:
ui-config:
submit-methods:
其他配置
swagger:
ui-config:
json-editor: false # json编辑器
request-timeout: 5000 # 页面调试请求的超时时间
show-request-headers: true # 显示请求头
更多配置说明见官方说明:https://github.com/SpringForAll/spring-boot-starter-swagger
在整合完Swagger之后,在http://localhost:8080/swagger-ui.html
页面中可以看到,关于各个接口的描述还都是英文或遵循代码定义的名称产生的。这些内容对用户并不友好,所以我们需要自己增加一些说明来丰富文档内容。我们通过@Api
,@ApiOperation
注解来给API增加说明、通过@ApiImplicitParam
、@ApiModel
、@ApiModelProperty
注解来给参数增加说明。
如下所示:
UserController.java 类
/**
*
* @ClassName: UserController
* @Description: 用户管理Controller
* @author YuanXu
* @date 2019年10月31日 下午4:49:00
*
*/
@Api(tags = "用户管理")
@RestController
@RequestMapping(value = "/users") // 通过这里配置使下面的映射都在/users下
public class UserController {
/**
* 创建线程安全的Map,模拟users信息的存储
*/
static Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());
@GetMapping("/")
@ApiOperation(value = "获取用户列表")
public List<User> getUserList() {
List<User> r = new ArrayList<>(users.values());
return r;
}
@PostMapping("/")
@ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
public String postUser(@RequestBody User user) {
users.put(user.getId(), user);
return "success";
}
@GetMapping("/{id}")
@ApiOperation(value = "获取用户详细信息", notes = "根据url的id来获取用户详细信息")
public User getUser(@PathVariable Long id) {
return users.get(id);
}
@PutMapping("/{id}")
@ApiImplicitParam(paramType = "path", dataType = "Long", name = "id", value = "用户编号", required = true, example = "1")
@ApiOperation(value = "更新用户详细信息", notes = "根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
public String putUser(@PathVariable Long id, @RequestBody User user) {
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}
@DeleteMapping("/{id}")
@ApiOperation(value = "删除用户", notes = "根据url的id来指定删除对象")
public String deleteUser(@PathVariable Long id) {
users.remove(id);
return "success";
}
}
User.java 类
/**
*
* @ClassName: User
* @Description: 用户 实体
* @author YuanXu
* @date 2019年10月31日 下午4:53:23
*
*/
@Data
@ApiModel(description = "用户实体")
public class User {
@ApiModelProperty("用户编号")
private Long id;
@ApiModelProperty("用户姓名")
private String name;
@ApiModelProperty("用户年龄")
private Integer age;
}
完成上述代码添加后,启动Spring Boot程序,访问:http://localhost:8080/swagger-ui.html
,就能看到中文说明的文档了。
打开API文档页面地址:http://localhost:8080/swagger-ui.html
API文档JSON数据获取地址:http://localhost:8080/v2/api-docs
Zuul工程pom.xml
引入依赖
<!-- 引入 springboot parent ,帮我们实现了很多jar包的依赖管理 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入spring-cloud-starter-zuul的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!-- 引入spring-cloud-starter-netflix-eureka-client的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入swagger-spring-boot-starter的依赖 -->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
</dependencies>
添加DocumentationConfig.java
类
通过遍历eureka路由方式自动添加所有微服务 API 文档,SwaggerResourcesProvider 是资源提供者,我们重写他,把各个微服务的API文档资源路径返回,注释部分为手动添加的方式。
/**
*
* @ClassName: DocumentationConfig
* @Description: Zuul整合Swagger2汇总API接口文档
* @author Yuan
* @date 2019年11月1日 上午10:30:37
*
*/
@Primary
@Component
public class DocumentationConfig implements SwaggerResourcesProvider {
private final RouteLocator routeLocator;
public DocumentationConfig(RouteLocator routeLocator) {
this.routeLocator = routeLocator;
}
/*
* (非 Javadoc)
* <p>Title: get </p>
* <p>遍历eureka路由方式自动添加所有微服务API文档</p>
* <p>Author: yuan </p>
* @return
* @see com.google.common.base.Supplier#get()
*/
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<SwaggerResource>();
List<Route> routes = routeLocator.getRoutes();
routes.forEach(route -> {
resources.add(swaggerResource(route.getId(), route.getFullPath().replace("**", "v2/api-docs"), "1.0"));
});
return null;
}
/*
* (非 Javadoc)
* <p>Title: get </p>
* <p>手动添加微服务API文档</p>
* <p>Author: aa </p>
* @return
* @see com.google.common.base.Supplier#get()
*/
/*
* @Override
* public List<SwaggerResource> get() {
* List resources = new ArrayList<>();
* resources.add(swaggerResource("基础服务API文档", "/yx-base-service/v2/api-docs", "1.0"));
* resources.add(swaggerResource("文件服务API文档", "/yx-file-service/v2/api-docs", "1.0"));
* return resources;
* }
*/
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
查看API整合效果
运行相关服务和zuul网关服务
浏览器输入:http://localhost:8090/swagger-ui.html
可查看API文档整合后的效果