Swagger
学习目标
- 了解Swagger的概念及作用
- 掌握在项目中集成Swagger自动生成API文档
1、Swagger简介
前后端分离
- 前端 -> 前端控制层、视图层
- 后端 -> 后端控制层、服务层、数据访问层
- 前后端通过API进行交互
- 前后端相对独立且松耦合
产生的问题
- 前后端集成,前端或者后端无法做到“及时协商,尽早解决”,最终导致问题集中爆发
解决方案
- 首先定义schema [ 计划的提纲 ],并实时跟踪最新的API,降低集成风险
Swagger
- 号称世界上最流行的API框架
- Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新
- 直接运行,在线测试API
- 支持多种语言 (如:Java,PHP等)
- 官网:https://swagger.io/
2、SpringBoot集成Swagger
SpringBoot集成Swagger => springfox,两个jar包
- Springfox-swagger2
- swagger-springmvc
使用Swagger
要求:jdk 1.8 + 否则swagger2无法运行
步骤:
1、新建一个SpringBoot-web项目
2、添加Maven依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
3、编写HelloController,测试确保运行成功!
4、要使用Swagger,我们需要编写一个配置类-SwaggerConfig来配置 Swagger
@Configuration //配置类
@EnableSwagger2// 开启Swagger2的自动配置
@EnableWebMvc//SpringBoot和swagger版本不匹配出现空指针异常,使用该注解解决
public class SwaggerConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
/** 配置knife4j 显示文档 */
registry.addResourceHandler("doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
/**
* 配置swagger-ui显示文档
*/
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
/** 公共部分内容 */
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
5、访问测试 :http://localhost:8080/swagger-ui.html ,可以看到swagger的界面;
6、可以看到swagger官网有几大模块内容
- 组
- 基本信息
- 接口信息
- 实体类信息
2.1 配置基本信息
Swagger 有自己的实例 Docket,如果我们想要自定义基本信息,可以使用 docket 来配置 swagger 的基本信息,基本信息的设置在 ApiInfo
这个对象中。
Swagger 默认的基本信息展示:
ApiInfo 中默认的基本设置
- title:Api Documentation
- description:Api Documentation
- version:1.0
- termsOfServiceUrl:urn:tos
- contact:无
- license:Apache 2.0
- licenseUrl:http://www.apache.org/licenses/LICENSE-2.0
SwaggerConfig.java
配置文件添加以下内容:
//配置docket以配置Swagger具体参数
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
// 配置基本信息
.apiInfo(apiInfo())
;
}
//配置文档信息
private ApiInfo apiInfo() {
Contact contact = new Contact("韦杰豪", //作者名称
"https://blog.csdn.net/weixin_49023961?type=blog", //作者网址
"2827673986@qq.com"); //作者邮箱
return new ApiInfoBuilder()
.title("韦杰豪Swagger接口API") // 标题
.description("众里寻他千百度,慕然回首那人却在灯火阑珊处") // 描述
.termsOfServiceUrl("https://www.baidu.com") // 跳转连接
.version("1.0") // 版本
.license("Swagger-的使用(详细教程)")
.licenseUrl("https://blog.csdn.net/weixin_49023961?type=blog")
.contact(contact)
.build();
}
重启服务,打开 Swagger 文档,基本信息改变如下所示:
2.2 配置接口信息
默认情况下,Swagger 是会展示所有的接口信息的,包括最基础的 basic-error
相关的接口
有时候我们希望不要展示 basic-error-controller
相关的接口,或者是说这想要显示某些接口,比如说com.itheima.controller
下的接口,由该怎么去实现呢?这个时候就需要设置 扫描接口
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
// 配置接口信息
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
//.any() // 扫描全部的接口,默认
//.none() // 全部不扫描
.basePackage("com.itheima.controller") // 扫描指定包下的接口,最为常用
//.withClassAnnotation(RestController.class) // 扫描带有指定注解的类下所有接口
//.withMethodAnnotation(PostMapping.class) // 扫描带有只当注解的方法接口
)
//paths:过滤接口
.paths(PathSelectors
.any() // 满足条件的路径,该断言总为true
//.none() // 不满足条件的路径,该断言总为false(可用于生成环境屏蔽 swagger)
//.ant("/user/**") // 满足字符串表达式路径
//.regex("") // 符合正则的路径
)
.build();
}
可根据自己的需求去设置对应的配置,这里我就不再一一赘述了,以上是我所设置的配置,重启服务,打开 Swagger 文档,接口信息改变如下所示:
2.3 配置分组信息
Swagger 默认只有一个 default 分组选项,如果没有设置,所有的接口都会显示在default
分组下,如果功能模块和接口数量一多,就会显得比较凌乱,不方便查找和使用。
swagger 文档中组名默认是 default
,可通过 .groupName(String )
//配置docket以配置Swagger具体参数
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
.groupName("韦杰豪")
// 配置基本信息
.apiInfo(apiInfo())
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
//.any() // 扫描全部的接口,默认
//.none() // 全部不扫描
.basePackage("com.itheima.controller") // 扫描指定包下的接口,最为常用
//.withClassAnnotation(RestController.class) // 扫描带有指定注解的类下所有接口
//.withMethodAnnotation(PostMapping.class) // 扫描带有只当注解的方法接口
)
.paths(PathSelectors
.any() // 满足条件的路径,该断言总为true
// .none() // 不满足条件的路径,该断言总为false(可用于生成环境屏蔽 swagger)
// .ant("/user/**") // 满足字符串表达式路径
//.regex("") // 符合正则的路径
)
.build();
}
如果需要配置多个组的话,就需要配置多个 docket() 方法
,这里我就简单写两组,代码如下:
/**
* 展示 controller 包下所有的接口
*/
@Bean
public Docket docket1() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
.groupName("mike") // 修改组名为 "mike"
// 配置接口信息
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
.basePackage("com.duojiala.mikeboot.controller") // 扫描指定包下的接口,最为常用
)
.paths(PathSelectors
.any() // 满足条件的路径,该断言总为true
)
.build();
}
/**
* 展示路径为 /error 的所有接口(基础接口)
*/
@Bean
public Docket docket2() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
.groupName("yank") // 修改组名为 "yank"
// 配置接口信息
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
.any() // 扫描全部的接口,默认
)
.paths(PathSelectors
.ant("/error") // 满足字符串表达式路径
)
.build();
}
重启服务,打开 Swagger 文档,接口信息改变如下所示:
组名为 mike
的文档中只有 user-controller
相关的接口信息
组名为 yank
的文档中只有 basic-error-controller
相关的接口信息
组名为 mike
的文档
2.4 控制Swagger的开关
在开发或者测试环境下,我们开启 swagger 会方便前端和后端的交互,但是如果在生产环境下也开启 swagger 的话,是会将接口暴露出去的,有极大风险,如何让 swagger 根据不同的环境来决定是否开启?
这里我准备了四个项目的配置文件,dev
、test
、pro
三个环境的配置文件仅是端口上的不同
- application.yml -------------------------- 全局配置文件
- application-dev.yml -------------------- 开发环境配置文件
- application-test.yml -------------------- 测试环境配置文件
- application-pro.yml -------------------- 生产环境配置文件
application.yml
内容如下,用于指定选择的环境:
spring:
profiles:
active: dev
可以通过代码判断此时是在什么环境:dev
、test
、pro
,如果是在 pro
生产环境,则关闭 swagger。
/**
* swagger 配置
* @param environment 环境
*/
@Bean
public Docket docket(Environment environment) {
// 设置环境范围
Profiles profiles = Profiles.of("dev","test");
// 如果在该环境返回内则返回:true,反之返回 false
boolean flag = environment.acceptsProfiles(profiles);
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
.enable(flag) // 是否开启 swagger:true -> 开启,false -> 关闭
;
}
在 application.yml
全局配置文件中环境指向 dev
时,是可以打开 swagger 的
如果我将 application.yml
全局配置文件中环境指向 pro
时,就不能打开 swagger 了,提示 Could not render e, see the console
拓展
通过enable()方法配置是否启用swagger,如果是false,swagger将不能在浏览器中访问了
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(false) //配置是否启用Swagger,如果是false,在浏览器将无法访问
.select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
.apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
// 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
.paths(PathSelectors.ant("/kuang/**"))
.build();
}
2.5 实体类的配置
1、新建一个实体类
@ApiModel("图书实体")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@ApiModelProperty("图书ID")
private Integer id;
@ApiModelProperty("图书类型")
private String type;
@ApiModelProperty("图书名称")
private String name;
@ApiModelProperty("图书描述信息")
private String description;
}
2、只要这个实体在请求接口的返回值上(即使是泛型),都能映射到实体项中:
@RequestMapping("/getUser")
public User getUser(){
return new User();
}
3、重启查看测试
注:并不是因为@ApiModel这个注解让实体显示在这里了,而是只要出现在接口方法的返回值上的实体都会显示在这里,而@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的。
@ApiModel为类添加注释
@ApiModelProperty为类属性添加注释
3、常用注解
@Api:修饰整个类,描述Controller的作用
@ApiOperation:描述一个类的一个方法,或者说一个接口
@ApiParam:单个参数描述
@ApiModel:用对象来接收参数
@ApiModelProperty:用对象接收参数时,描述对象的一个字段
@ApiImplicitParam:一个请求参数
@ApiImplicitParams:多个请求参数
下面列一些经常用到的,未列举出来的可以另行查阅说明:
Swagger注解 | 简单说明 |
---|---|
@Api(tags = “xxx模块说明”) | 作用在模块类上 |
@ApiOperation(“xxx接口说明”) | 作用在接口方法上 |
@ApiModel(“xxxPOJO说明”) | 作用在模型类上:如VO、BO |
@ApiModelProperty(value = “xxx属性说明”,hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
@ApiParam(“xxx参数说明”) | 作用在参数、方法和字段上,类似@ApiModelProperty |
我们也可以给请求的接口配置一些注释
@ApiOperation("狂神的接口")
@PostMapping("/kuang")
@ResponseBody
public String kuang(@ApiParam("这个名字会被返回")String username){
return username;
}
这样的话,可以给一些比较难理解的属性或者接口,增加一些配置信息,让人更容易阅读!
4、接口调用
使用 swagger 除了让前后端交互变得方便,也让接口的请求变得简单,只需要填写好请求所需要的参数信息,便可直接发起请求。
比如说接口 /user/query-user-info
点击 Try it out
设置好请求所需的参数,点击 Execute
执行
就能看到接口响应的结果了
接口 /user/query-user-infos
也差不多
5、进阶使用
1. 添加请求头
有时候我们的接口是需要获取请求头信息的,这样的话就还需要在 swagger 配置中添加请求头的配置。
@Bean
public Docket docket() {
// 设置请求头
List<Parameter> parameters = new ArrayList<>();
parameters.add(new ParameterBuilder()
.name("token") // 字段名
.description("token") // 描述
.modelRef(new ModelRef("string")) // 数据类型
.parameterType("header") // 参数类型
.defaultValue("default value") // 默认值:可自己设置
.hidden(true) // 是否隐藏
.required(false) // 是否必须
.build());
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
.groupName("mike") // 修改组名为 "mike"
// 配置接口信息
.select() // 设置扫描接口
// 配置如何扫描接口
.apis(RequestHandlerSelectors
.basePackage("com.duojiala.mikeboot.controller") // 扫描指定包下的接口,最为常用
)
.paths(PathSelectors
.any() // 满足条件的路径,该断言总为true
)
.build()
// 添加请求头参数
.globalOperationParameters(parameters);
}
比如接口:
@GetMapping(value = "/get-token")
@ApiOperation(value = "获取请求头中的token信息")
public void getToken(
@RequestHeader(value = "token",required = false) String token
) {
// 直接获取 token 信息
System.out.println("token = " + token);
// 通过代码获取
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes != null) {
HttpServletRequest request = servletRequestAttributes.getRequest();
String header = request.getHeader("token");
System.err.println("header = " + header);
}
}
可以看到这个接口已经可以去设置请求头了,调用接口