大家好,今天我们开始一个新专题 — Swagger。
关于 Swagger 相信我们都在实际项目开发中使用过,它的核心知识点完全可以整理成一组专题来展开介绍,本专题我们重点讲解 Swagger 在基于 Java 生态框架的日常开发过中如何来应用。
本文我们主要先介绍一下 Swagger 是什么?有哪些特性?优缺点在哪?为什么我们需要在项目开发中应用 Swagger ?
什么是 Swagger 呢?在 Swagger 官网中是这么介绍的:
Swagger 就是一种可以帮助我们简化 API 开发过程的工具。 — 官网
我们看到,这里提到了 API 这一术语,在业界,API 一般指的是:通过后端编码而开发出来的,且可以供其他用户所使用的一种专门对外暴露的数据传输接口,即我们可以通过编写 API 来达到和用户交互的目的。俗话说无规矩不成方圆,针对 API 业界也制定了一款标准,那就是 RESTFUL API 规范,下面我们来简单介绍一下什么是 RESTFUL API 规范:
RESTFUL
的全称是 Representational State Transfer,即表述性状态转换,或者我们可以通俗的理解为:一组具有约束条件和原则的规范。
也就是说:RESTFUL API 就是经过一组确定好的具有约束行为和统一原则的规范来规定 API 书写规则、命名规则、请求规则、响应规则的一种表述性方式。通过这个方式我们可以很好地理解具体 API 所代表的的业务场景和返回字段的含义。
通过上面的介绍,说白了,Swagger 就是一款可以简化项目 API 开发的工具,用来帮助我们通过最简单的途径来开发 RESTFUL API。
那么我们为什么要使用 Swagger 呢?
如果我们需要在项目中使用 Swagger,那么我们只需要将 Swagger 的依赖集成到项目中去,然后通过一个简单的 Swagger 配置类即可开始使用了,不需要像其他工具那样还要繁琐的去配置 xml,即配置简单,容易上手。这为我们节省了大量的时间,使得我们可以把时间用在集中处理项目业务上,提升我们的开发效率。
Swagger 通过内置 html 解析器的方式来实现将 RESTFUL API 显示在界面上供开发者查看,Swagger 提供的界面样式即简洁又美观,开发者可以很直观地看到自己所编写的 RESTFUL API 的请求方式、请求参数、返回格式以及所属业务组,如下图所示。
我们在开发 Java 项目的时候,主要的目的就是对外暴露我们的数据传输接口,来实现前后台数据交互的目的。
针对于我们编写的接口,往往我们需要撰写接口文档来说明具体接口所做的业务是什么,以及这个接口如何使用。这样在无形之中就加重了我们的工作内容,而有了 Swagger 之后,我们只需要在相应的地方添加 Swagger 的注解来对接口进行简单的说明,它就会帮助我们生成一份完整的接口说明,见上图。
这样一来我们就不用再编写一份几十页甚至几百页的接口文档了,提升了交互性能,同时也提升了前后台开发者的沟通效率。
总结:
Swagger 它是一个帮助开发人员来简化开发 RESTFUL API 的一款开发工具,其核心是基于 NPM 实现,在 Spring 项目中则是通过封装 SpringFox 依赖来完成对接口请求方式、请求参数、响应数据的加载,最终通过前端界面的方式来展现给用户。Swagger 具有简单、方便、高效的特性,用 Swagger 构建 RESTFUL API 可快速又方便。
Swagger 从 2011 年发布至今已经有 9 个年头,期间已经迭代升级了很多版本,现在最新的版本是 v3.18.3,每个版本都有不同的特性,下面主要介绍一个主要使用的版本和新版本的特性。
V1.0.1 - 1.0.13: 最初发布版本,基本已经很少使用了。
V2.X.X: 目前使用较多的版本,也是我们这个课程使用的版本。
V3.18.3: 目前发布的最新版本,2018 年 8 月 3 日发布的。主要是优化了接口组的使用方法、美化了 RESTFUL API 界面显示效果。最新版本可能会导致部分项目无法正常使用,这个时候需要回退到 2.X.X 版本即可。
导出格式灵活 : 支持 Json 和 yml 来编写 API 文档,并且支持导出为 json、yml、markdown 等格式。
跨语言支持性 : 只针对 API,而不针对特定语言的 API,很多自动生成 API 的工具基本都是只针对特定的 API。
界面清晰易懂 : 界面清晰,无论是 Editor 的实时展示还是 Swagg-UI 界面的展示都十分人性化,简单明了。
无法自定义界面 : Swagger-UI 封装好了一套 Html 模板,任何 RESTFUL API 的展示形式只能遵循其格式,不能灵活修改。
官方文档不全面 : Swagger 官方针对不同的模块提供了不同的介绍文档,但是缺乏系统的介绍,不利于新人学习。
学习这门课程首先要有基于 Java 生态框架开发项目的经验,可以是使用 Java 框架开发项目的新人,也可以是具有丰富项目开发经验的老司机。
本套课程是用 SpringBoot 的方式,通过 Maven 包管理工具来快速使用 SpringBoot 框架,所以没有接触过 SpringBoot 框架和 Maven 包管理工具的同学请自行了解。
本节是本套课程的开端,主要介绍了什么是 Swagger ,为什么使用 Swagger ,以及 Swagger 优缺点等。
本套课程主要针对 Swagger-UI 在 SpringBoot 开发框架中的使用,本节内容是学习本套课程的开端。
在本节中将为大家介绍如何使用 SpringBoot 来集成 Swagger-UI ,包括集成 Swagger-UI 的具体详细步骤,以及在集成过程中的一些注意事项。
重点讲解内容:
SpringBoot 主流开发框架与 Swagger-UI 工具的集成步骤。
集成过程中的一些经验和注意事项、Swagger-UI 不同版本与 SpringBoot 框架兼容问题。
我们知道,使用 Maven 来创建的项目会有专门的一个 pom.xml 文件,这个文件是我们项目中所有用到的工具包的一个列表,在 java 中被称作 jar 包。在 Maven 中通过引入不同的 jar 包坐标配置来将相应的工具集成到我们的项目中。
所以当我们需要在项目中集成某种工具时,我们需要将该工具对应的坐标放到 Maven 的 pom.xml 文件中去。
通过访问 Maven 的中央仓库我们可以搜索到 Swagger-UI 对应 SpringBoot 框架适合的坐标数据,如下 Maven 坐标所示:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
在上述 Maven 坐标中,第一个 springfox-swagger2 依赖,为 Swagger 2 的核心依赖,即我们如果想使用 Swagger 工具,则必须要在项目中引入该依赖,如果我们没有引入该依赖,那么我们是不能在项目中使用 Swagger 的。
而 springfox-swagger-ui 这一依赖,就是我们本文所介绍的 Swagger-UI 的依赖,如果我们不引入该依赖,我们是不会看到 Swagger 的 API 管理界面的。
在将上述两个 Swagger 的坐标数据放到我们项目的 pom.xml 文件中去之后,我们就完成了集成 Swagger-UI 的准备工作。
这样引入的 Swagger-UI 我们只能使用它的注解,而这时所产生的 Swagger-ui 界面我们是看不懂的,因为我们还没有对界面增加我们的规定,所以接下来让我们完成 Swagger-UI 的一些基本配置。
由于 SpringBoot 框架简化了传统 Spring MVC 框架中繁琐的 xml 文件配置,所以我们在对 Swagger-UI 进行配置时只需要使用两个注解和一个配置类即可完成,SpringBoot 为我们提供了两种配置方法,让我们来看一下吧。
Tips : 在接下来的两种配置方法中,主要介绍 Swagger-UI 的集成注解,而对于配置类我会单独进行详细讲解,请同学们注意。
Swagger-UI 官方针对 SpringBoot 框架推出了很方便的开放 API ,我们在引入了 Swagger-UI 的 Maven 坐标之后,只需要在 SpringBoot 应用的启动类的上方加入开启 Swagger-UI 的注解即可在项目中来使用 Swagger-UI。
在上图中,我添加了 @EnableSwagger2 注解,这正是 Swagger-UI 官方在 SpringBoot 框架中提供的开启使用 Swagger-UI 的注解。
当我们在项目的启动类上方添加了 @EnableSwagger2 注解之后就表示我们可以在项目中来使用 Swagger-UI 了。
Tips : 如果我们只引入了 Swagger-UI 的依赖,没有配置 @EnableSwagger2 注解,那么在项目中我们也是无法使用 Swagger-UI 的,这一点需要同学们特别注意。
对于 Swagger-UI 的配置类来说,我们只需要新建一个配置类并将该配置类通过添加 @Configuration 注解来注入到我们的项目中即可。
以上是配置 Swagger-UI 的第一种方法,即通过 @EnableSwagger2 注解与 @Configuration 注解相分离的方式来配置,这种配置方式相对来说好理解一些。
Tips:
各位同学在集成 Swagger-UI 时,依赖的版本请务必和老师保持一致,避免由于版本原因而出现的未知问题。
SpringBoot 框架版本请选择 SpringBoot 2.0.X.RELEASE 及以上版本或 SpringBoot 的里程碑版本。
@Configuration 注解贯穿整个 SpringBoot 框架,有不懂的同学请自行了解。
在第一种方式中我们将两个注解进行了分开配置,这种方法通俗易懂,而在本方式中,会将两个注解集中来配置。
我们新建一个类,名为 Swagger2Config ,这个类就是我们后续要讲的 Swagger-UI 配置类了,然后我们在该类的最上方添加上述两个注解:
在上图中,我们通过在启动类中添加 @Configuration 注解的方式将配置类以及 Swagger-UI 的所有注解来一起注入到我们项目中去,这与第一种方式的不同之处在于:
第一种方式, @EnableSwagger2 注解的声明没有通过 @Configuration 注解来处理,而是通过 SpringBoot 应用去自动装配;第二种方式则是将配置类和 Swagger-UI 的所有注解都通过 @Configuration 注解来处理,不通过 SpringBoot 应用去自动装配。
而上述两种方式并不会影响项目的正常运行,所以我们采用任何一种方式都是可取的。
在本部分中,老师将带领大家针对 Swagger-UI 常用的基本配置属性以及其他额外属性进行详细讲解,下面我们来看一下 Swagger-UI 都需要在 SpringBoot 框架中配置哪些属性(所有属性都根据官方配置演变而来)。
创建 Swagger 应用配置:
代码解释:
createRestApi 方法的返回值是一个 Docket 类型,该类型就是返回 Swagger-Documentation 类型的数据,大家不用关心。
在方法内部,使用匿名内部类的方式实例化了一个 Docket 对象并返回,DocumentationType 即文档类型的选择我们需要根据集成的 Swagger 的版本来选择,这里选择 SWAGGER_2 表示使用的 Swagger 是2.X系列版本。
apiInfo() 和 select() 这两个方法是配置 Swagger 应用的必要方法,我们只需要这样理解就可以了:集成必要的 API 信息(apiInfo() 方法)来供我们查询(select() 方法)使用。
apis() 方法里面通过 RequestHandlerSelectors.basePackage() 属性来描述我们的目标包,就是我们项目中接口所在包的完整目录名称,这样 Swagger 就可以扫描到了,如果不配置此项,Swagger 是扫描不到我们项目中的接口的。
paths() 方法就是规定将我们项目中所有接口的请求路径都暴露给 Swagger 来生成 Swagger-UI 界面。
build() 方法就是将我们设置的上述参数都放到返回的 Docket 实例中。
创建 Swagger-UI 界面基本信息配置:
代码解释:
apiInfo 方法返回 Swagger-ApiInfo 类型,大家可以理解为返回 Swagger-UI 界面的基本信息就行了。在方法内部也是通过匿名内部类的方式返回一个 ApiInfo 实例。
title() 方法:就是来规定我们的 Swagger-UI 界面的大标题。
description() 方法:就是来规定对 Swagger-UI 界面的一些简单描述信息。
contact() 方法:就是来规定创建 Swagger-UI 的作者的名称,目前已被废弃。
version() 方法:就是来规定 Swagger-UI 界面上所有接口的版本。
build() 方法:就是将我们设置的上述参数都放到返回的 ApiInfo 实例中。
通过上述两个方法的配置,我们就完成了 Swagger-UI 的基本配置,启动项目之后,在浏览器地址栏中输入访问路径(一般为项目 ip 地址:端口/swagger-ui.html)就可以在浏览器中看到 Swagger-UI 的界面效果了。
Tips:
访问路径中的 swagger-ui.html 为默认固定写法,一般不用修改。
createRestApi() 方法为 public 方法,即这个方法需要对外暴露才行,而 apiInfo() 方法为 private 私有方法;该方法的用途是配置 Swagger-UI 界面基本信息,只能在项目中进行配置,不能将配置权限暴露出去。
在 apiInfo() 方法中我们不需要写太多的信息,因为一些必要的信息都是在接口中来描述的。
本小节从 Swagger-UI 集成准备工作开始,到不同的配置集成方式,再到最后对 Swagger 配置类的详细阐述,从零到一的对 SpringBoot 如何集成 Swagger-UI 进行了详细的讲解,旨在帮助大家能够准确的集成 Swagger-UI ,对于在集成中容易出现的问题,老师也做了相应的提醒和解决建议,希望各位同学都能成功在 SpringBoot 中集成 Swagger-UI。
针对 Swagger-UI 界面上的每一个组成元素在这里就不系统介绍了,后面会有专门的小节来对 Swagger-UI 界面的组成元素以及如何使用 Swagger-UI 进行简单必要的接口调试进行系统性地详细介绍,请各位同学关注。
本节会结合一个用户登录接口给大家介绍 Swagger 中核心注解之一 ApiOperation 及所提供的常用属性。
ApiOperation 注解在 Swagger 中扮演着非常重要的角色,基本上只要使用 Swagger 那就必须要用 ApiOperation 注解。
重点讲解的属性:value 、tags 、notes ;
概要讲解的属性:httpMethod、nickname、protocols、hidden、code。
希望大家在学习本节过程中能够分清主次,有的放矢。
在我们日常工作中,后端小伙伴们经常会写一些接口,为了方便让大家知道这些接口的功能作用,我们就需要给接口添加一些具体的描述信息,为此,在 Swagger 中,我们就需要使用 ApiOperation 注解来描述我们写的接口。
ApiOperation 注解提供了丰富的属性来允许我们自定义接口描述信息,包括接口名称,接口所属分组等。
下面我们来看一下 ApiOperation 注解中都包括哪些主要属性。(注意:我们只介绍还在使用的属性,那些被 Swagger 官方已经废弃的属性不再介绍)。
属性名称 | 属性类型 | 默认值 | 作用 |
---|---|---|---|
value() | String | 空 | 接口说明 |
tags() | String[] | 空 | 定义接口分组 |
notes() | String | 空 | 接口发布说明 |
httpMethod() | String | 空 | 接口请求方式 |
nickname() | String | 空 | 接口别名 |
protocols() | String | 空 | 网络请求协议 |
hidden() | boolean | false | 接口隐藏 |
code() | int | 200 | 接口状态码 |
response() | Class<?> | Void.class | 接口返回类型 |
responseContainer() | String | 空 | 接口返回数据类型 |
responseReference() | String | 空 | 接口返回引用类型 |
produces() | String | 空 | 接口请求头类型 - 输出 |
consumes() | String | 空 | 接口请求头类型 - 输入 |
定义:
该属性就是描述接口的作用是什么,即接口是用来干什么的。
使用方法:
在 ApiOperatio 注解中声明 value 的值即可。例如,就用户登录接口而言,只需要将 value 的值写为 '用户登录’就好了,这样我们就能很清楚的知道这个接口就是来做用户登录用的,如下代码段所示(现在你不需要理解业务代码代表什么意思,重点看方法上使用的注解及属性即可,下同)。
@ApiOperation(value = "用户登录")
public CommonResponse<User> userLogin(HttpSession session, @RequestBody User user){
return userService.login(session, user);
}
代码解释:
第 1 行,我们在 userLogin 方法的上方使用了 @ApiOperation 的 value 属性来描述接口的作用。
显示结果:
在结果显示界面的右上角就是我们使用 value 属性描述的信息(用户登录)。
Tips : 项目中的接口文档可能需要看的人很多,不只是开发人员看,客户有时候也要看,所以 value 属性值的描述,应该本着通俗易懂的原则进行,一定要根据接口方法实现的具体业务内容来描述,不能随便描述,不能使用表意不清楚的词语来描述,更不能使用专业术语来描述。
定义:
该属性就是对实现相同业务场景的接口做一个分组。
使用方法:
在 ApiOperatio 注解中声明 tags 的值即可,如果没有描述则默认值为空。例如,就用户登录接口而言,该接口属于用户业务分组中,所以我们将 tags 的值描述为'用户’或者'user’,这样我们就能很清楚的看到这个接口是属于用户业务组的,如下代码段所示。
@ApiOperation(tags = {"user"})
public CommonResponse<User> userLogin(HttpSession session, @RequestBody User user){
return userService.login(session, user);
}
代码解释:
第 1 行,我们在 userLogin 方法的上方使用了 @ApiOperation 注解的 tags 属性来描述接口所属的业务分组。
显示结果:
我们可以看到在顶部有一个 user 字样,这个就是我们规定的分组名称,也就是 tags 里写的 user 了。
Tips:
在实际项目开发工作中,往往一个接口可能涉及多个业务,这种情况需要我们对接口进行多个分组,而 tags 属性的类型是字符串类型的数组,可以描述一个或多个值,如存在多值时,应该使用如下方法来描述。
tags 属性值的描述规则同上述 value 属性。
@ApiOperation(tags = {"user", "customer"})
定义:
该属性就是对接口方法做进一步详细的描述。
使用方法:
在 ApiOperatio 注解中声明 notes 的值即可,如果没有描述则默认值为空。例如,如果我想添加对用户登录接口的详细描述信息,那么我可以这样写 notes = “用户登录接口必须是 post 请求”,这种使用效果会直接显示在接口面板中,当做接口的主要内容进行显示,如下代码段所示。
@ApiOperation(notes = {"用户登录接口必须是post请求"})
public CommonResponse<User> userLogin(HttpSession session, @RequestBody User user){
return userService.login(session, user);
}
代码解释:
第 1 行,我们在 userLogin 方法的上方使用了 @ApiOperation 注解的 notes 属性来进一步描述接口的详细信息。
显示结果:
在我用红框圈起来的地方我们可以看到 Implementation Notes 下放就是我们对该接口的进一步详细描述,其显示在了接口的主要内容区域里面。
Tips :
notes 属性一般用来描述接口的一些必要详细信息,如果是一般的信息则最好不要使用 notes 去描述。
使用 notes 属性来进一步详细描述接口这一行为往往在项目开发中不是必须的。
以上是对 ApiOperation 注解中经常使用的三个属性进行的详细介绍,value,tags,notes 这三个属性不管是在项目开发中,还是在需求沟通中,使用的都很频繁,所以,真正掌握这三个属性是用好 Swagger 的重要前提。在学习这三个属性时,大家应该自己对比并总结它们之间的差异,通过不断的使用来发现它们的使用规律,这一点很重要。
在详细讲解完 ApiOperation 重要属性之后,下面我将针对在 ApiOperation 注解中,使用频率不是很高,但是有时也会用到的一些属性做概要性讲解,这些属性分别是:httpMethod、nickname、protoclos、hidden、code。
定义:
httpMethod () 属性就是对接口的请求类型进行一个约定,常用的接口类型有:“GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS”。
nickname () 属性是为接口起一个别名,方便前后端沟通使用。
使用方法:
httpMethod () 属性默认值为空,但是 Swagger 在处理时会默认获取项目所采用的接口请求类型,我们可以不用专门设置,如果一定要设置该属性,则只允许设置 http 协议规定的属性,不能随意设置。
nickname () 属性允许我们为接口设置一个别名,在设置别名之后,我们设置的别名会出现在浏览器地址栏中,如下代码段所示(httpMethod () 属性自动获取值,这里不再演示)。
@ApiOperation(nickname = "userLoginNickName")
public CommonResponse<User> userLogin(HttpSession session, @RequestBody User user){
return userService.login(session, user);
}
代码解释:
第 1 行,我们在 userLogin 方法的上方使用了 @ApiOperation 注解的 nickname 属性来为接口起一个别名。
显示结果:
在我用红框圈起来的地方我们可以看到 userLoginNickName 字样,这就是我们为接口所设置的别名。
Tips :
不要随意定义接口的别名,要根据特定业务场景来设置。
在项目前后端联合测试过程中,给接口起一个别名更方便前后端开发人员的沟通,并没有其他特殊意义。
定义:
protocols () 属性就是对接口所使用的网络协议进行一个约定,常用的网络协议有:http、https。
hidden () 属性就是控制接口在 Swagger 界面中的显隐性。
code () 属性就是控制接口的返回状态,常见的有:200,201,404,500 等。
使用方法:
protocols () 属性默认值为空,但是 Swagger 在处理时会默认获取项目所采用的网络协议,我们可以不用专门设置,如果一定要设置该属性,则只允许设置 http 协议规定的属性,不能随意设置,http, https, ws, wss 这些都是被允许的。
code () 属性一般不用特定设置, Swagger 会自动生成接口返回状态,这里不再演示。
hidden () 属性允许我们在 Swagger 生成的接口列表界面上控制接口是否需要显示,默认值为 false,即接口显示,为 true 时则接口不显示,如下代码段所示。
@ApiOperation(hidden = true)
public CommonResponse<User> userLogin(HttpSession session, @RequestBody User user){
return userService.login(session, user);
}
代码解释:
第 1 行,我们在 userLogin 方法的上方使用了 @ApiOperation 注解的 hidden 属性来隐藏我们的接口。
显示结果:
可以看到在接口列表界面,已经看不到我们的用户登录接口了,这就是当 hidden 属性设置为 true 时所起的作用。
Tips :
接口的显隐控制应该根据特定安全策略和特定客户需求来决定显隐,不能无故隐藏接口,更不能频繁的切换接口的显隐。
在实际工作中,如果需要隐藏接口则需要和项目组报备情况,说明原因。
以上则是 ApiOperation 注解中的辅助使用属性的概要介绍,对于剩下的 response、responseContainer、responseReference、produces、consumes 属性在实际项目开发中几乎很少使用,在这里就不再介绍了,如果大家感兴趣可以去 Swagger 的官网查询相关资料来了解。
本小节对 Swagger 中最经常使用的 ApiOperation 注解及其该注解的各个属性做了详细的讲解,针对 ApiOperation 注解中经常在实际项目开发中使用的属性采用图文并茂的方式进行了重点介绍和应用剖析,对于一些在实际项目开发中使用基本很少的注解做了概要讲解。通过这样系统的讲解,希望大家从注解属性的定义到具体使用规范全过程中彻底搞懂 ApiOperation 注解及其注解各属性的语义规则、使用场景、注意事项等。
联系客服