WebFlux 中使用 Swagger
因为工作需要,重新调研了 Swagger。WebFlux 使用 Swagger 和之前有一些不同,而且我发现网络上基本没有这方面的中文资料,因此写篇文章记录一下。
Swagger 是非常常用的 API 文档工具,就我观察,好像所有需要写接口文档的 Java 项目都在使用它。从某种程度上讲,Swagger 可以代表接口文档,因为它实在是太主流了,而且它提出的规范也变成了行规,更何况它还在积极向前迭代。
网上对于 Swagger 和行业规范 OpenAPI 的描述有点混乱,我试着整理了一下:
- Swagger 在 2011 年出现,目前(2020.7)的版本是 2.X
- Swagger 将自己的规范捐献给 Linux 基金会,改名为 OpenAPI Specification(OAS),目前的版本是 3
- 网络上普遍将 Swagger 1.X 称为 2.0,而将 2.X 称为 3.0,具体原因不明,因此搜索最新的 Swagger 时,你需要搜索 Swagger 3.0(或者放弃用中文搜索)
- Swagger 1.X 和 2.X 在逻辑上是一致的,在使用上注解名都换了,在规范上做了更新(但是用户感受不到)
大家使用 Swagger 基本都是在 Spring 项目中使用的,但是 Spring 官方并没有集成 Swagger,因此目前大家使用的都是开源世界的第三方轮子。有两个比较常见的依赖库:
- SpringFox,最常见,但是至今它还没有支持 Spring 5,因此如果想在 WebFlux 中使用 Swagger,你还不能选择这个。
- SpringDoc,支持 WebFlux,本篇文章就是在说怎么使用 SpringDoc。
SpringDoc 有一大堆的 Swagger 实现,适配了诸如 Spring MVC、Spring WebFlux、Swagger-UI 等等一堆的内容,官方给的 demo 里面就有接近十个不同的项目,我也没太看明白,在反复尝试之后,得出一组在 WebFlux 上能够使用的 Maven 依赖:
1 | <dependency> |
(具体的官方文档可以点击 SpringDoc)
理论上引入 Maven 依赖之后就可以直接使用了,启动地址是 …/swagger-ui.html(在我们的项目里是 …/webjars/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/,不太明白原因)。
SpringDoc 的各项参数基本都可以在 application.properties
中进行配置,就比如上面的地址,默认配置就是:
1 | springdoc.swagger-ui.path=/swagger-ui.html |
更多的配置信息可以参考官方文档《Configuration of springdoc-openapi》。
Swagger 2.X 使用的注解全都变了,尽管使用逻辑没变,但是名字都不一样了。
如果你对原来的 Swagger 很熟悉,那么可以参考《Migrating from SpringFox》,这是 SpringDoc 官方整理的一份文档,描述了怎么从 SpringFox 迁移过来(因为 SpringFox 使用旧的 Swagger 1.X,这文档整理得可以说是杀人诛心了233)
如果你对原来的 Swagger 不是很熟悉,或者印象不深了,可以参考 Swagger 2.X 在 github 上的官方使用文档《Swagger 2.X Annotations》。
国内使用 Swagger 2.X 的导读文章还比较少,唯一一篇我觉得有价值的是《springboot 集成 springdoc-openapi-ui》。
下面我简单整理几个常用的注解:
@Tag
可用在类或方法前(一般是类前),用于给多个接口归类(某些接口在同一组内),相当于 Swagger2 的 @Api
。
属性 | 作用 | 数据类型 | 备注 | 是否必填 | 默认值 |
---|---|---|---|---|---|
name | 名称 | String | 如果多个 @Tag 使用相同的 name ,那么将归到同一个组中 |
√ | |
description | 描述 | String | 如果多个 @Tag 的 name 相同归到同一个组,仅能使用一个 description ,否则会发生覆盖 |
× | “” |
externalDocs | 额外说明文档 | ExternalDocumentation(注解) | 一般用不到,可以附文字、网址进行补充说明,内容详见下文 @ExternalDocumentation 注解 |
× | @ExternalDocumentation() |
Extension | 没用 |
使用示例:
1 | "本Controller的名字", description = "这里是一些描述", (name = |
@Operation
可用在方法前,主要用于描述接口,相当于 Swagger 的 @ApiOperation
。
属性 | 作用 | 数据类型 | 备注 | 是否必填 | 默认值 |
---|---|---|---|---|---|
summary | 摘要(实际代表着名字的作用) | String | 在 Swagger 中,展示在接口 URL 旁边,建议必写 | × | “” |
description | 描述 | String | 在 Swagger 中,点击接口详情可看到 | × | “” |
requestBody | 请求体 | RequestBody(注解) | 使用比较繁冗,建议不使用 | × | @RequestBody() |
responses | 返回体 | ApiResponse[](注解数组) | 使用比较繁冗,建议不使用 | × | {} |
externalDocs | 一般用不上,用法同 @Tag 内的使用方法 |
||||
tags | 建议不用,当类没有 @Tag 注解时,将使用此处的 tags 属性分成指定的多组,使用上容易出错 |
||||
method | 用不上 | ||||
operationId | 用不上 | ||||
deprecated | 用不上,完全可以用 Java 自己的 @Deprecated 注解代替 |
||||
ignoreJsonView | 用不上 | ||||
extensions | 用不上 | ||||
parameters | 用不上 | ||||
security | 用不上 | ||||
servers | 用不上 | ||||
hidden | 用不上 |
使用示例:
1 | // 如果采用自定义的VO类,来接收和返回值,那么代码将很紧凑 |
@Schema
主要用于描述实体类和变量(也可应用在其他注解之中,但代码冗余,不建议)
属性 | 作用 | 数据类型 | 备注 | 是否必填 | 默认值 |
---|---|---|---|---|---|
name | 替换原名 | String | 不要使用,它会替换掉原字段名称,例如变量名 userId 注 name = "用户ID" ,变量名在前端的展示将不再是 userId ,而是用户ID |
× | “” |
description | 描述 | String | 最常使用,请在每处都使用它 | × | “” |
example | 样例 | String | 示例,建议使用 | × | “” |
required | 是否必填 | boolean | × | false | |
其他(好多) | 建议不使用,可自行斟酌 |
使用示例:
1 |
|
写一个简单的小 demo:
1 | /* —————————————————————— 定义两个类,用于接收和返回 —————————————————————— */ |
Swagger 的配置文件(Config.java)是可有可无的,因为大多数的配置,都可以使用上文提到的 application.properties
中配置,这跟在 Spring Boot 中使用其他依赖工具的方式是一样的。
如果你还是想用一个 Java 文件单独配置的话,可以参考下面这段代码:
1 |
|
它实现了两个配置:
- Swagger 可视化网站的名称等配置。
- 配置了鉴权(请求参数中携带 Authorization 作为 token)
值得一提的是,上面这两个配置,一个使用注解,一个使用方法,其实是可以互换的,也就是说每一种配置都是可以使用注解或方法来配置的,看个人喜好。
最终的效果如下图所示:
研究 Swagger 配置鉴权花了不少时间,主要也是因为自己没有做过鉴权相关的东西。
总体的思路是,在配置文件中事先配置好,并给这个部分起一个名字(因为可以有多个鉴权)。在想使用的 Controller 层或者方法层上,加上一行注解,指定想要使用的鉴权的名字,就可以使用啦。
比如针对上面的配置文件(名字叫做 authorization
),就可以在 Controller 上面加上这么一行注解,这样在 Swagger 中调用方法时,这个 Controller 里面的所有方法都会在请求参数里带上 Authorization
。
1 | "authorization") (name = |
就整理这么多吧。