文章目录
Swagger 的使用
前言
后端时代
- 前端:只用管理静态页面:html。
- 后端:模板引擎 JSP,后端是主力
前后端分离时代
主流框架:Vue + SpringBoot
- 后端:后端控制层,服务层,数据访问层【后端团队】
- 前端:前端控制层,视图层【前端团队】
- 伪造后端数据:json假数据。不需要请求后端,仅前端工程已经可以启动并操作。
前后端通过 API 接口进行交互,相对独立,松耦合,可以部署在不同的服务器上
前端后分离存在的问题:
- 前后端集成联调,前端人员和后端人员无法做到“及时协商,尽早解决”,最终导致问题集中爆发;
解决方案:
- 首先制定
schema
(计划的提纲),试试更新最新API
,降低集成风险; - 早期:制定word计划文档;
- 前后端分离:
- 后端接口测试工具:
postman
- 后端向前端提供接口,需要实时更新罪行的消息及改动!
- 后端接口测试工具:
Swagger 简介
- 号称世界上最流程的
Api
框架; - 在线自动生成
RestFul Api
文档,该文档与Api
接口信息同步更新; - 直接运行,可在线测试
Api
接口; - 支持多种语言:
Java、Php ...
官网:
https://swagger.io/
使用:
- 在项目中使用 Swagger 需要两个 springfox 依赖:
springfox-swagger2
springfox-swagger-ui
SpringBoot 集成 Swagger 2.x
-
新建一个
SpringBoot
项目(web
项目); -
导入依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> <exclusions> <exclusion> <!-- io.springfox:springfox-swagger2:2.9.2中依赖了swagger-models的1.5.20版本, 通过排除springfox-swagger2中的swagger-models依赖,导入io.swagger:swagger-models的1.5.22版本. 解决io.swagger.models.parameters.AbstractSerializableParameter实例化参数时example为空字符串""而报错的问题. 因为1.5.20的example只判断是否为null,1.5.22判断了是否为null和"" --> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/io.swagger/swagger-models --> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.22</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>
-
编写一个
Hello
工程; -
在主程序上添加注解,开启
Swagger2
@SpringBootApplication //开启 Swagger2 @EnableSwagger2 public class SwaggerDemoApplication { public static void main(String[] args) { SpringApplication.run(SwaggerDemoApplication.class, args); } }
-
测试运行,访问 Swagger UI 界面
http://localhost:8080/swagger-ui.html
SpringBoot 集成 Swagger 3.0
-
新建一个 SpringBoot 项目(web项目);
-
导入依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-boot-starter --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>
-
编写一个
Hello
工程; -
在主程序上添加注解,开启Swagger
@SpringBootApplication //开启 Swagger @EnableOpenApi public class SwaggerDemoApplication { public static void main(String[] args) { SpringApplication.run(SwaggerDemoApplication.class, args); } }
-
测试运行,访问 Swagger UI 界面 注意:路径同
Swagger 2.x
不同http://localhost:8080/swagger-ui/index.html
配置 Swagger
配置文档信息
Swagger 的 bean 实例:Docket
Docket.apiInfo(ApiInfo apiInfo)方法
具体配置
@Configuration
public class SwaggerConfig {
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
/**
* 配置 swagger 的信息:ApiInfo
*
* @return ApiInfo 的 bean实例
*/
public ApiInfo apiInfo() {
//作者信息
Contact contact = new Contact("小聪", "https://blog.csdn.net/weixin_52610802?type=blog", "coder_cong@163.com");
return new ApiInfo("Aladdin的SwaggerAPI文档",
"不负韶华,未来可期",
"V1.0",
"https://blog.csdn.net/weixin_52610802?type=blog",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
配置扫描接口
Docket.select()方法
具体配置
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
/*
RequestHandlerSelectors 配置扫描接口的方式
basePackage():指定要扫描的包(通常指定包扫描)
any():扫描全部
none():不扫描
withMethodAnnotation():扫描方法上的注解
withClassAnnotation():方法类上的注解
*/
.apis(RequestHandlerSelectors.basePackage("com.aladdin.swagger.controller"))
/*
PathSelectors 请求路径匹配的方式
regex():正则匹配
any():扫描全部
none():不扫描
ant():路径匹配
*/
.paths(PathSelectors.ant("/aladdin/**"))
.build();
}
配置功能是否启动
Docket.enable(boolean externallyConfiguredFlag)方法
具体配置
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否启动 Swagger,如果为 false,则 UI界面提示:【😱 Could not render e, see the console.】,无法在浏览器中访问 Swagger
.enable(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.aladdin.swagger.controller"))
.paths(PathSelectors.ant("/aladdin/**"))
.build();
}
实用案例
- 根据服务环境动态配置 Swagger 是否开启。
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket(Environment environment) {
//配置要显示 Swagger 的环境
Profiles profiles = Profiles.of("dev", "test");
//通过environment.acceptsProfiles()方法判断当前是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否开启 Swagger,如果为 false,则 UI界面提示:【😱 Could not render e, see the console.】,无法在浏览器中访问 Swagger
.enable(flag)
.select()
.apis(RequestHandlerSelectors.basePackage("com.aladdin.swagger.controller"))
.paths(PathSelectors.ant("/aladdin/**"))
.build();
}
配置 API 文档的分组
Docket.groupName(String groupName)方法
具体配置
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket(Environment environment) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(true)
//设置组名称,一个 Docket bean 对应一个组名称
.groupName("阿拉丁")
.apis(RequestHandlerSelectors.basePackage("com.aladdin.swagger.controller"))
//.paths(PathSelectors.ant("/aladdin/**"))
.build();
}
配置多个分组
配置多个分组,需配置多个 Docket bean
,每个 bean
配置各自的 groupName
。
package com.aladdin.swagger.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
@Configuration
public class SwaggerConfig {
/**
* 配置 Swagger Docket 的 bean实例
*
* @return Docket 的 bean实例
*/
@Bean
public Docket docket(Environment environment) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(true)
.groupName("阿拉丁")
.select()
.apis(RequestHandlerSelectors.basePackage("com.aladdin.swagger.controller"))
//.paths(PathSelectors.ant("/aladdin/**"))
.build();
}
/**
* 配置 swagger 的信息:ApiInfo
*
* @return ApiInfo 的 bean实例
*/
public ApiInfo apiInfo() {
//作者信息
Contact contact = new Contact("阿拉丁", "https://blog.csdn.net/weixin_52610802?type=blog", "coder_cong@163.com");
return new ApiInfo("Aladdin的SwaggerAPI文档",
"不负韶华,未来可期",
"V1.0",
"https://blog.csdn.net/weixin_52610802?type=blog",
contact,
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
@Bean
public Docket docket1() {
return new Docket(DocumentationType.SWAGGER_2).groupName("分组1");
}
@Bean
public Docket docket2() {
return new Docket(DocumentationType.SWAGGER_2).groupName("分组2");
}
@Bean
public Docket docket3() {
return new Docket(DocumentationType.SWAGGER_2).groupName("分组3");
}
}
模型类模块(Models)
-
Swagger
页面Models
模块为实体类信息 -
如果
Swagger
分组扫描的接口返回值存在实体类,则此实体类就会被扫描到该分组中-
新建实体类
public class User { private String username; private String password; ... }
-
增加返回值为
User
类的接口@RestController public class HelloController { @GetMapping("/hello") public String hello() { return "Hello"; } @PostMapping("/user") public User user() { return new User("123", "qwe"); } }
-
重启项目,访问
Swagger
页面,则会看见Models
中加载了User
实体类
-
文档注释
可使用 Swagger
注解为生成的 Api
在线文档添加注释信息
作用范围 | API | 使用位置 |
---|---|---|
描述返回对象的意义 | @ApiModel | 用在返回对象类上 |
对象属性 | @ApiModelProperty | 用在出入参数对象的字段上 |
作用范围 | API | 使用位置 |
---|---|---|
协议集描述 | @Api | 用于controller类上 |
协议描述 | @ApiOperation | 用在controller的方法上 |
Response集 | @ApiResponses | 用在controller的方法上 |
Response | @ApiResponse | 用在 @ApiResponses里边 |
非对象参数集 | @ApiImplicitParams | 用在controller的方法上 |
非对象参数描述 | @ApiImplicitParam | 用在@ApiImplicitParams的方法里边 |
-
@Api
:用在controller上,对controller进行注释; -
@ApiOperation
:用在API方法上,对该API做注释,说明API的作用; -
@ApiResponses
:通常用来包含接口的一组响应注解,可以简单的理解为响应注解的集合声明; -
@ApiResponse
:用在@ApiResponses中,一般用于表达一个错误的响应信息;- code:即httpCode,例如400;
- message:信息,例如"请求参数没填好";
即使只有一个@ApiResponse,也需要使用@ApiResponses包住。
-
@ApiImplicitParams
:用来包含API的一组参数注解,可以简单的理解为参数注解的集合声明; -
@ApiImplicitParam
:用在 @ApiImplicitParams 注解中,也可以单独使用,说明一个请求参数的各个方面,该注解包含的常用选项有:属性 取值 作用 paramType 查询参数类型 path 以地址的形式提交数据 query 直接跟参数完成自动映射赋值 body 以流的形式提交 仅支持POST header 参数在request headers 里边提交 form 以form表单的形式提交,仅支持POST dataType 参数的数据类型 只作为标志说明,并没有实际验证 Long String name 接收参数名 value 接收参数的意义描述 required 参数是否必填 true 必填 false 非必填 defaultValue 默认值代码 - form域中的值需要使用@RequestParam获取
- header域中的值需要使用@RequestHeader来获取
- path域中的值需要使用@PathVariable来获取
- body域中的值使用@RequestBody来获取,否则可能出错;而且如果paramType是body,name就不能是body,否则有问题,与官方文档中的
“If paramType is "body", the name should be "body"
不符。
Swagger Demo
部分示范代码
package com.aladdin.swagger.pojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("用户实体类")
public class User {
@ApiModelProperty(value = "用户名", example = "123123", required = true)
private String username;
@ApiModelProperty(value = "密码", example = "aaa123", required = true)
private String password;
...
}
package com.aladdin.swagger.controller;
import com.aladdin.swagger.pojo.User;
import io.swagger.annotations.*;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@Api("Hello 控制类")
@RestController
public class HelloController {
@ApiOperation("测试query")
@ApiResponses({@ApiResponse(code = 1000, message = "操作成功"),
@ApiResponse(code = 9999, message = "系统异常"),
@ApiResponse(code = 8888, message = "权限不足")})
@ApiImplicitParams({@ApiImplicitParam(paramType = "query", dataType = "String", name = "str", value = "字符串", required = true)})
@GetMapping("/hello")
public String hello(String str) {
return "Hello: " + str;
}
@ApiOperation("测试path")
@ApiImplicitParams({@ApiImplicitParam(paramType = "path", dataType = "Long", name = "id", value = "信息id", required = true)})
@GetMapping("/hello2/{id}")
public String hello2(@PathVariable("id") Long id) {
return "Hello: " + id;
}
@ApiOperation("测试header")
@ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "Long", name = "id", value = "信息id", required = true)})
@GetMapping("/hello3")
public String hello3(@RequestHeader("id") Long id) {
return "Hello: " + id;
}
@ApiOperation("测试form")
@ApiImplicitParams({ @ApiImplicitParam(paramType = "form", dataType = "Long", name = "id", value = "信息id", required = true) })
@PostMapping(value = "/hello4", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String hello4(@RequestParam("id") Long id) {
return "Hello: " + id;
}
@ApiOperation("测试body")
@ApiImplicitParams({@ApiImplicitParam(paramType = "body", dataType = "User", name = "user", value = "用户信息参数", required = true)})
@PostMapping("/user")
public User user(@RequestBody User user) {
return user;
}
}
总结
- 可通过 Swagger 给一些比较难理解的属性或者接口增加注释信息;
- 接口文档实时更新;
- 可以在线测试。
注意:出于安全考虑,在正式发布的时候,关闭 Swagger,同时也会节省运行内存。