最近为项目引入Swagger
来支持自动生成文档功能,发现很多文章仅仅介绍了如何接入以及如何使用的问题。但是对于实际工程实践,并没有给出相应的最佳实践方案。因此,我重新梳理相关内容以及文档,整理出一套最佳实践指南。
Swagger和Springfox
在正式介绍之前,我们首先要了解Swagger
和Springfox
之间的关系。相信在Spring
项目使用过Swagger
的同学都知道,在Spring
项目中是通过Springfox
来整合Swagger
功能的。
Swagger是什么
根据官网的介绍,Swagger
是一系列用于Restful API
开发的工具,开源的部分包括:
- OpenAPI Specification:API规范,规定了如何描述一个系统的API
- Swagger Codegen:用于通过API规范生成服务端和客户端代码
- Swagger Editor:用来编写API规范
- Swagger UI:用于展示API规范
简单来说,我们可以认为swagger
主要制定并实现了一个API
规范,用于描述系统的API
接口。
Springfox是什么
简单来说,Springfox
其实是一个通过扫描并提取代码中的信息,来生成API
文档的工具,支持swagger
、RAML
、jsonapi
等多种API
文档的格式。因为我们这里着重讨论swagger
,因此我们可以简单理解为:Springfox
就是整合SpringMVC
和swagger
的中间层,以支持自动扫描Controller
层的接口来生成符合swagger
API规范的描述数据(JSON
格式)。
通过Springfox
,已经可以将swagger
与SpringBoot
项目整合起来了,网上有一大堆整合的文章,这里就不再赘述了,具体可以参考SpringBoot整合Swagger实战。并且官方最近也出了3.0
版本,具体可以参考:还在手动整合Swagger?Swagger官方Starter是真的香!。
knife4j简介
虽然直接通过Springfox
已经可以实现SpringBoot
接入Swagger
生成接口文档。但是这种方式有两个弊端:
- 原生接口文档页面展示不够友好。
- 使用起来可能比较繁琐。
因此,在这里强烈推荐使用Knife4j
。Knife4j
是Swagger
接口文档服务的通用性解决方案,底层基于Springfox
实现。最主要的两个特性如下:
- 重写了前端UI界面,更符合国人使用习惯。
- 支持快速接入,并提供了很多实用功能增强。
- 文档友好,直接参考
Knife4j
官网文档就能完成接入。
能让用户以最低成本接入的方式就是最好的方式,而Knife4j
确实实现的非常好。更多详细信息可以参考官方文档https://xiaoym.gitee.io/knife4j/documentation/description.html。
最佳实践指南
实际上,SpringBoot
的Controller
层方法已经包含描述该接口详细信息了。当然,因为我们要补充中文说明。因此,最为理想的状况是,接口文档直接能直接根据Controller
层的方法自动生成,我们顶多为每个参数编写一个中文说明,仅此而已。
我觉得完全自描述的接口才是最合理的,同时也是最简便的。但是,理想很好,现实情况是Springfox
对此支持的并不算太好。因此,我们需要在实践的时候,找到一种方式来解决这个问题,下面会介绍一些常见问题的解决思路。
2.x和3.x版本如何选择
Knife4j
的2.x
版本对应Springfox
的2.x
版本,其采用的是Swagger2
规范,相应的3.x
版本使用的OpenAPI3
规范。关于这两个规范,我们不需要了解太多细节,只需要知道OpenAPI3
规范能够更准确描述接口就行。而对于Springfox
而言,3.x
版本还有一个优势是:对于Bean Validation
支持更好,能够从接口自身解析出更详细的接口信息。因此,如果条件允许,强烈建议3.x
版本!我甚至觉得,如果是2.x
版本,接入的价值都不大。我始终觉得,在一个本身已经自描述的接口上,再去专门为文档去写各种注释是一件本末倒置的事情。既然已经自描述,那么最佳的解决方案永远都是框架去解析,而不是人工再写一遍!!!
以下是一个2.x
和3.x
版本,对同一接口生成的接口文档,相信大家看完会有一个自己的判断!
2.x
版本:
3.x
版本:
3.x
版本能解析出更多的接口信息,描述更为准确。
对请求体入参支持不够好
对于Query
查询参数,Springfox
的3.x
版本已经支持的非常好了,我们按之前的方式写接口即可。但是对于请求体参数,现有框架支持的还是不够好。其中,最为典型的是不支持分组校验。这样的导致的结果就是,文档上会将整个DTO
类的字段以及约束全部展示到任何一个使用了该DTO
接收参数的接口上。很明显,这并不合理,因为分组校验做的就是让该接口指定分组下的约束只对这个接口生效。
针对这个问题,有什么完美的解决方案吗?答案是没有,这里只能做一个取舍。如果十分看重接口文档准确性的话,只能不使用分组校验,这样的话,意味着每个接口的请求体都要用不同的DTO
类来接收,以防止互相干扰。如果不是特别在意,那还是按分组校验来写,实现更简单。目前,我们项目准备选第一种方式。
如果不了解参数校验,可以戳这里:Spring Validation最佳实践及其实现原理,参数校验没那么简单!。对于参数校验,强烈建议这种注解式的方式。因为只有注解式,才能真正做到接口自描述。
接入和使用示例
引入依赖
1 | <dependency> |
编写接口
只需要额外再为每个字段加中文说明即可!
1 |
|
一般来说,生产环境并不需要开启接口文档功能,只需要在生产环境加如下配置即可:
1 | springfox: |
常用文档注解
使用文档注解的目的只是为了添加中文说明,仅此而已!
注解 | 说明 | 示例 |
---|---|---|
@Api |
标注在Controller 上,用于给控制器添加中文说明 |
@Api(tags = “Person管理”) |
@ApiOperation |
标注在方法上,用于给请求添加中文说明 | @ApiOperation(“保存用户”) |
@ApiParam |
标注在方法参数上,用于给请求参数添加中文说明 | @ApiParam(“用户id”) |
@ApiModel |
标注在DTO 实体类上,用于给请求体添加中文说明 |
@ApiModel(“保存用户DTO类”) |
@ApiModelProperty |
标注在DTO 实体类的字段上,用于给请求体字段添加中文说明 |
@ApiModelProperty(“姓名”) |
示例截图
源码
源码地址:https://github.com/chentianming11/spring-validation
启动项目,访问http://localhost:8080/doc.html可查看接口文档。
原创不易,觉得文章写得不错的小伙伴,点个赞👍 鼓励一下吧~
欢迎关注我的开源项目:一款适用于SpringBoot的轻量级HTTP调用框架