Spring Boot项目使用Swagger2文档教程
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
前言
Spring Boot 框架是目前非常流行的微服务框架,我们很多情况下使用它来提供 Rest API。而对于 Rest API 来说很重要的一部分内容就是文档,Swagger 为我们提供了一套通过代码和注解自动生成文档的方法,这一点对于保证 API 文档的及时性将有很大的帮助。
本文将使用 Swagger 2 规范的 Springfox 实现来了解如何在 Spring Boot 项目中使用 Swagger,主要包含了如何使用 Swagger 自动生成文档、使用 Swagger 文档以及 Swagger 相关的一些高级配置和注解。
Swagger简介
Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计、构建、记录以及使用 Rest API。
Swagger 的 OpenAPI 规范与编程语言无关,根据 OpenAPI 规范可以生成 Swagger 文档。
Swagger 文档支持 YAML 语法和 JSON 语法,这两种语法风格可以相互转换,都可以用来对我们的 RESTful API 接口的信息进行准确描述,便于人类和机器阅读。
Swagger组成
如图所示,Swagger 主要包含了以下三个部分:
1.Swagger Editor:基于浏览器的 Swagger 文档编辑器,我们可以使用它编写我们 OpenAPI 规范文档。
官方提供的在线编辑器截图如下:
2.Swagger UI:它会将我们编写的 OpenAPI 规范文档呈现为交互式的 API 文档,后文我将使用浏览器来查看并且操作我们的 Rest API,你也可以访问官方提供的 Demo 率先体验。
3.Swagger Codegen:它可以通过为 OpenAPI(以前称为 Swagger)规范定义的任何 API 生成服务器存根和客户端 SDK 来简化构建过程。
Swagger原理
Swagger 的大致原理是通过 Swagger Editor 或者嵌入到代码中的注解来生成具有 OpenAPI 规范的 Swagger 文档,即 swagger.json 或 swagger.yaml 文件,然后交给 Swagger UI 和 Swagger Codegen 使用并生成相应服务,如下图所示。
Swagger优势
传统意义上的文档都是后端开发人员手动编写的,相信大家也都知道这种方式很难保证文档的及时性,这种文档久而久之也就会失去其参考意义,反而还会加大我们的沟通成本。而 Swagger 给我们提供了一个全新的维护 API 文档的方式,下面我们就来了解一下它的优点:
- 代码变,文档变。只需要少量的注解,Swagger 就可以根据代码自动生成 API 文档,很好的保证了文档的时效性。
- 跨语言性,支持 40 多种语言。
- Swagger UI 呈现出来的是一份可交互式的 API 文档,我们可以直接在文档页面尝试 API 的调用,省去了准备复杂的调用参数的过程。
- 还可以将文档规范导入相关的工具(例如 SoapUI), 这些工具将会为我们自动地创建自动化测试。
以上这些优点足以说明我们为什么要使用 Swagger 了,您是否已经对 Swagger 产生了浓厚的兴趣了呢?下面我们就将一步一步地在 Spring Boot 项目中集成和使用 Swagger,让我们从准备一个 Spring Boot 的 Web 项目开始吧。
准备 Spring Boot 项目
首先通过 IDEA 创建一个空白的 Spring Boot 项目,然后添加 Web 依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
编写接口
- 首先我们创建三个包:
com.example.swagger.controller
、com.example.swagger.config
以及com.example.swagger.vo
。 - 在 controller 包下新建
UserController.java
类,在 config 包下新建Swagger2Config.java
类,在 vo 包下新建User.java
类。 UserController
提供用户的增、删、改、查四个接口,代码我会在后面和Swagger集成后贴出来。User
用户实体类包括用户的ID(整型)、姓名(字符串)和年龄(整型)。
集成 Swagger2
添加依赖
首先要做的自然是添加 Swagger2 的依赖。
<!-- 理论上导入这一个包就可以 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
笔者在测试的发现该依赖的子依赖 swagger-annotations
和 swagger-models
的版本有些 bug,所以最好还是手动升级这两个依赖的版本。
<!-- 但是需要手动升级这两个包的版本减少一些bug -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.22</version>
</dependency>
最后呢,我们还需要添加 swagger ui
模块用于生成与浏览器交互的文档,这里我们选择非官方的 swagger-bootstrap-ui
框架。
<!-- 最后使用非官方swagger-ui框架 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
配置信息
接下里,我们通过配置 Swagger2Config 类添加文档信息。在这一步中,不仅需要配置 @EnableSwagger2
注解开启 Swagger2 文档页面,还需要配置 Docket 类的对象实例,并初始化必要的参数,包括文档的标题、摘要、版本、开发者信息。
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
// API文档简介
.apiInfo(new ApiInfoBuilder()
.title("Spring Boot中使用Swagger2构建RESTFul APIs")
.description("这是一段简介说明")
.termsOfServiceUrl("http://github.com/ystcode")
.contact(new Contact("薛勤", "https://ystblog.com", "yster@foxmail.com"))
.version("1.0")
.build())
// 如果存在多个Docket实例,则每个实例都必须具有此方法提供的唯一组名称。默认值为"default"。
.groupName("example")
// 构建 ApiSelectorBuilder 的第一步
.select()
// 自定义包扫描
.apis(RequestHandlerSelectors.any())
// 过滤到的才有效
.paths(PathSelectors.any())
// 构建 ApiSelectorBuilder 的最后一步
.build();
}
}
接口过滤
有些时候我们并不是希望所有的 Rest API 都呈现在文档上,这种情况下 Swagger2 提供给我们了两种方式配置,一种是基于 @ApiIgnore
注解,另一种是在 Docket 上增加筛选。
如果想在文档中屏蔽掉删除用户的接口(user/delete),那么只需要在删除用户的方法上加上 @ApiIgnore 即可。
在 Docket 上增加筛选。Docket 类提供了
apis()
和paths()
两 个方法来帮助我们在不同级别上过滤接口:
apis()
:这种方式我们可以通过指定包名的方式,让 Swagger 只去某些包下面扫描。paths()
:这种方式可以通过筛选 API 的 url 来进行过滤,匹配的才会显示。
在集成 Swagger2 的章节中我们这两个方法指定的都是扫描所有,没有指定任何过滤条件。如果我们在我们修改之前定义的 Docket 对象的 apis()
方法和 paths()
方法为下面的内容,那么接口文档将只会展示 /user/add 和 /user/find/{id} 两个接口。
.apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
.paths(Predicates.or(PathSelectors.ant("/user/add"),PathSelectors.ant("/user/find/*")))
自定义响应消息
Swagger 允许我们通过 Docket 的 globalResponseMessage()
方法全局覆盖 HTTP 方法的响应消息,但是首先我们得通过 Docket 的 useDefaultResponseMessages
方法告诉 Swagger 不使用默认的 HTTP 响应消息,假设我们现在需要覆盖所有 GET 方法的 500 和 404 错误的响应消息,我们只需要在 Swagger2Config.java 类中的 Docket Bean 下添加如下内容:
// 自定义响应消息的说明
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.GET, Arrays.asList(
new ResponseMessageBuilder()
.code(500)
.message("服务器发生异常")
.responseModel(new ModelRef("ServiceError"))
.build(),
new ResponseMessageBuilder()
.code(404)
.message("资源不存在")
.responseModel(new ModelRef("RequestError"))
.build()
)
)
添加如上面的代码后,如下图所示,等会运行你就会发现在 SwaggerUI 页面展示的所有 GET 类型请求的 404 以及 500 错误的响应消息都变成了我们自定义的内容。
默认参数
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
针对项目中的权限校验等情况,Swagger 还在 UI 界面为所有请求添加默认参数,位置可以是 header, cookie, body, query 等。
// 在UI界面为所有请求添加默认参数,Swagger不做处理,可以使用拦截器进行处理。
.globalOperationParameters(Arrays.asList(
new ParameterBuilder()
.name("auth")
.description("统一鉴权标识")
.scalarExample("abc")
.required(true)
.modelRef(new ModelRef("String"))
.parameterType("query")
.order(1)
.build()))
使用注解
到这里,我们的文档在全局上已经配置完成,但是我们还需要在细节上对接口进行描述。正如开头提到的,我们需要使用 Swagger 注解嵌入到代码中去完善 Swagger 文档信息。
@API
通过在控制器类上增加@Api
注解,可以给控制器增加标签和描述信息。
@Api(tags = "用户相关接口", description = "提供用户相关的 Rest API")
public class UserController {
private Map<Integer, User> userService = new ConcurrentHashMap<>();
}
值得一提的是,属性 description 已经被废弃,使用亦是无效的。
@ApiOperation
通过在接口方法上增加 @ApiOperation
注解来展开对接口的描述:
@PostMapping("/add")
@ApiOperation(value = "新增用户", notes = "根据User对象新增一位用户对象")
public User addUser(@RequestBody User user) {
userService.put(user.getId(), user);
return userService.get(user.getId());
}
@PutMapping("/update")
@ApiOperation(value = "更新用户", notes = "根据User对象更新一位用户数据")
public User update(@RequestBody User user) {
if (userService.containsKey(user.getId())) {
userService.put(user.getId(), user);
return userService.get(user.getId());
}
return null;
}
当然这个注解还可以指定很多内容,包括如下几个属性:
注解属性 | 类型 | 描述 |
---|---|---|
value | String | 接口说明。 |
notes | String | 接口发布说明。 |
tags | Stirng[] | 标签。 |
response | Class<?> | 接口返回类型。 |
httpMethod | String | 接口请求方式。 |
@ApiModel 和 @ApiModelProperty
@ApiModel
: 可设置接口相关实体的描述。@ApiModelProperty
: 可设置实体属性的相关描述。
我们可以通过 @ApiModel
和 @ApiModelProperty
注解来对我们 API 中所涉及到的对象做描述。
@ApiModel(value = "用户实体")
public class User {
@ApiModelProperty(value = "用户ID", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "用户姓名", example = "张三")
private String name;
@ApiModelProperty(value = "用户年龄", example = "18")
private Integer age;
}
当然这个注解还可以指定很多内容,包括如下几个属性:
注解属性 | 类型 | 描述 |
---|---|---|
value | String | 字段说明。 |
name | String | 重写字段名称。 |
dataType | Stirng | 重写字段类型。 |
required | boolean | 是否必填。 |
example | Stirng | 举例说明。 |
hidden | boolean | 是否在文档中隐藏该字段。 |
allowEmptyValue | boolean | 是否允许为空。 |
allowableValues | String | 该字段允许的值,当我们 API 的某个参数为枚举类型时,使用这个属性就可以清楚地告诉 API 使用者该参数所能允许传入的值。 |
@ApiImplicitParam
@ApiImplicitParams
: 用于描述接口的非对象参数集。@ApiImplicitParam
: 用于描述接口的非对象参数,一般与@ApiImplicitParams
组合使用。
我们可以使用 @ApiImplicitParam
注解对接口参数进行描述:
@GetMapping("/find/{id}")
@ApiOperation(value = "查询用户", notes = "根据ID查询一位用户数据")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "path")
})
// @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "path")
public User findById(@PathVariable("id") Integer id) {
if (userService.containsKey(id)) {
return userService.get(id);
}
return null;
}
@ApiParam
我们还可以使用 @ApiParam
注解对接口参数进行描述,这种方式更加简洁,推荐使用。
@DeleteMapping("/delete/{id}")
@ApiOperation(value = "删除用户", notes = "根据ID删除一位用户数据")
public User delete(
@ApiParam(value = "唯一ID", required = true)
@PathVariable("id") Integer id
) {
User user;
if ((user = userService.remove(id)) == null) {
return null;
}
return user;
}
运行项目
如下图所示,运行项目后访问 /doc.html
路径你就会发现在 SwaggerUI 页面的主页菜单栏下会出现我们自定义的这些信息,包括左上角设置的 GroupName。
正如我们刚开始讲解的 Swagger 原理,访问 /v2/api-docs?group=example
路径即可以看到生成的 JSON 格式的 Swagger 文档。
当你点击左侧“查询用户”菜单时,可以看到如下图所示的请求参数,除了参数 id 外,还包括我们设置的默认参数 auth。
点击左侧“新增用户”菜单,选择调试,可以看到已经为我们生成了模拟参数,我们可以直接点击“发送”进行调试。
结束语
在本教程中,我们学会了如何使用 Swagger 2 来生成 Spring Boot REST API 的文档。我们还研究了如何过滤 API、自定义 HTTP 响应消息以及如何使用 SwaggerUI 直接调用我们的 API。您可以在 Gitee 上找到本教程的完整实现,这是一个基于 IntelliJ IDEA 的项目,因此它应该很容易导入和运行,当然如果您想对本教程做补充的话欢迎发表评论或者直接在 Gitee 上提交 Pull Request。
参考文章
在 Spring Boot 项目中使用 Swagger 文档
版权声明
【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】
Spring Boot项目使用Swagger2文档教程的更多相关文章
- Spring Boot:整合Swagger文档
综合概述 spring-boot作为当前最为流行的Java web开发脚手架,越来越多的开发者选择用其来构建企业级的RESTFul API接口.这些接口不但会服务于传统的web端(b/s),也会服务于 ...
- swagger ui和spring boot集成生成api文档
作者:小莫链接:https://www.zhihu.com/question/28119576/answer/134580038来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- Spring Boot属性文件配置文档(全部)
This sample file is meant as a guide only. Do not copy/paste the entire content into your applicatio ...
- 如何运行Spring Boot项目
背景 帮别人指导一个Spring Boot项目,它在本地把项目push到git服务器上,然后在部署的服务器上把代码pull下来(我猜应该是这个流程) 然后他问我这项目怎么运行? 我当时就懵了,因为我平 ...
- Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档
0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...
- Spring Boot中使用Swagger2构建API文档
程序员都很希望别人能写技术文档,自己却很不愿意写文档.因为接口数量繁多,并且充满业务细节,写文档需要花大量的时间去处理格式排版,代码修改后还需要同步修改文档,经常因为项目时间紧等原因导致文档滞后于代码 ...
- Spring Boot中使用Swagger2自动构建API文档
由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...
- Spring Boot 中使用 Swagger2 构建强大的 RESTful API 文档
项目现状:由于前后端分离,没有很好的前后端合作工具. 由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型.HTTP头部信息.HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下 ...
- Spring Boot中使用Swagger2生成RESTful API文档(转)
效果如下图所示: 添加Swagger2依赖 在pom.xml中加入Swagger2的依赖 <!-- https://mvnrepository.com/artifact/io.springfox ...
随机推荐
- nvm的安装,安装node,npm
先说说我为什么使用nvm吧 最近在搞react-native,就碰到了很多坑,其中就有node带来的坑,当你运行react-native start (这是rn启动服务器的命令)就会报一个正则的错误, ...
- echarts的时间轴的提示内容写在轴下方
echarts的时间轴的提示内容写在轴下方 在echarts中横坐标的拖动轴dataZone的提示内容在两端,并且没有相关配置让其显示在轴下方或者其他位置. 解决方式: 在图标下方添加dom并且监听拖 ...
- (Java实现) N皇后问题
n皇后问题是一个以国际象棋为背景的问题:在n×n的国际象棋棋盘上放置n个皇后,使得任何一个皇后都无法直接吃掉其他的皇后,即任意两个皇后都不能处于同一条横行.纵行或斜线上. 蛮力法思想: 解决n皇后问题 ...
- Java实现 LeetCode 820 单词的压缩编码(字典树)
820. 单词的压缩编码 给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A. 例如,如果这个列表是 ["time", "me", & ...
- Java实现 蓝桥杯 算法提高 复数四则运算
算法提高 6-17复数四则运算 时间限制:1.0s 内存限制:512.0MB 提交此题 设计复数库,实现基本的复数加减乘除运算. 输入时只需分别键入实部和虚部,以空格分割,两个复数之间用运算符分隔:输 ...
- java实现第七届蓝桥杯路径之谜
路径之谜 题目描述 小明冒充X星球的骑士,进入了一个奇怪的城堡. 城堡里边什么都没有,只有方形石头铺成的地面. 假设城堡地面是 n x n 个方格.[如图1.png]所示. 按习俗,骑士要从西北角走到 ...
- linux性能监控工具nmon生成HTML报告-EasyNmon
一.关于easyNmon说明 为了方便多场景批量性能测试,用golang写了个监控程序,可以通过get url方式启动和停止nmon服务,非常适合配合Loadrunner性能测试框架和jmeter使用 ...
- 使用Java将阿拉伯数字转换为中文数字(适配小数转换)
Java数字转换工具类 简介 该工具类可以将整数.小数.负数转换为中文的数字,如: 0 --> 零 1 --> 一 2.1 --> 二点一 -2.1 --> 负二点一 具体代码 ...
- 移除VS解决方案中的TFS版本控制
项目每次会弹出提示 正在打开的解决方案已绑定到以下 Azure DevOps Server 上的源代码管理: xxxxx.是否要联系此服务器以尝试启用源代码管理集成? 移除VS解决方案中的TFS版本控 ...
- 聊一聊高并发高可用那些事 - Kafka篇
目录 为什么需要消息队列 1.异步 :一个下单流程,你需要扣积分,扣优惠卷,发短信等,有些耗时又不需要立即处理的事,可以丢到队列里异步处理. 2.削峰 :按平常的流量,服务器刚好可以正常负载.偶尔推出 ...