Swagger简介
前后端分离
-
前端 -> 前端控制层、视图层
-
后端 -> 后端控制层、服务层、数据访问层
-
前后端通过API进行交互
-
前后端相对独立且松耦合
产生的问题
- 前后端集成,前端或者后端无法做到“及时协商,尽早解决”,最终导致问题集中爆发
解决方案
-
首先定义schema [ 计划的提纲 ],并实时跟踪最新的API,降低集成风险
-
Swagger
-
号称世界上最流行的API框架
-
Restful Api 文档在线自动生成器 => API 文档 与API 定义同步更新
-
直接运行,在线测试API
-
支持多种语言 (如:Java,PHP等)
-
官网:https://swagger.io/
-
SpringBoot集成Swagger
使用Swagger
1. SpringBoot集成Swagger => springfox,两个jar包
- Springfox-swagger2
- swagger-springmvc
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<!-- 经测试,3.0.0不能启动swagger -->
<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>
2. 编写controller接口测试接口是否能正常运行
package com.qk.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/t1")
public String test01(){
return "hello swagger";
}
}
3. 编写配置类,开启swagger2
package com.qk.config;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class HelloSwagger {
}
- 访问:http://localhost:8080/swagger-ui.html
配置Swagger
1. 查看源码分析
2. 综上
@Configuration
@EnableSwagger2
public class HelloSwagger {
//配置swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2);
}
}
3. 在Docket中的除了参数DocumentationType,其他参数的默认值都可以修改
this.apiInfo = ApiInfo.DEFAULT;
this.groupName = "default";
this.enabled = true;
this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
this.applyDefaultResponseMessages = true;
this.host = "";
this.pathMapping = Optional.absent();
this.apiSelector = ApiSelector.DEFAULT;
this.enableUrlTemplating = false;
this.vendorExtensions = Lists.newArrayList();
4. 分析源码
- 自定义apiInfo
- 根据源码自定义 apiInfo(apiInfo())
@Configuration
@EnableSwagger2
public class HelloSwagger {
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo(){
return new ApiInfo("乾坤大挪移",
"Api Documentation by qk",
"9.9", "https://blog.csdn.net/qq_40429067",
new Contact("qk", "https://blog.csdn.net/qq_40429067", "[email protected]"),
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
}
配置扫描接口
构建Docket时通过select()方法配置怎么扫描接口
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//.select()和.build()必须同时存在,否则会报错,再在中间.apis或.paths(),选择扫描的方式
//RequestHandlerSelectors : 配置要扫描接口的方式
//basePackage : 指定要扫描的包
//any() : 扫描所有,项目中的所有接口都会被扫描到
//none() : 不扫描接口
//withMethodAnnotation() : 通过方法上的注解扫描,如:withMethodAnnotation(GetMapping.class)只扫描get请求
//withClassAnnotation() : 通过类上的注解扫描,如:withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
//basePackage() : 如:basePackage("com.qk.controller")只扫描com.qk.controller包下的接口
.apis(RequestHandlerSelectors.basePackage("com.qk.controller"))
//paths() :过滤什么路径,如:paths(PathSelectors.ant("/qk/**")),结合apis的扫描包的条件,扫描controller包下的带有"/qk/**"请求的接口
//any() 任何请求都扫描
//none() 任何请求都不扫描
//regex(final String pathRegex) 通过正则表达式控制
//ant(final String antPattern) 通过ant()控制
.paths(PathSelectors.ant("/qk/**"))
.build();
}
- 一个完整的配置扫描接口:扫描controller包下的带有"/qk/**"请求的接口
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.qk.controller"))
.paths(PathSelectors.ant("/t1/**"))
.build();
}
配置Swagger开关
- .select()、.apis()和.build() 是一套的,必须紧密相连,其他配置在它们上面配置,path()可有可无
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.qk.controller"))
.build();
}
通过enable()方法配置是否启用swagger,如果是false,swagger-ui.html将不能在浏览器中访问
根据当前运行的配置环境,决定是否开启swagger。如:开发环境下开启swagger,生产环境下不开启。
- 通过Docket(Environment)中的Environment获取配置文件中当前激活的环境
@Bean
public Docket docket(Environment environment){
// 设置要显示swagger的环境,可以设置多个,只要满足一个返回值就为true,开启swagger
Profiles of = Profiles.of("dev", "pro");
// acceptsProfiles()需要一个Profiles类型的参数,所以在上面创建一个,而Profiles返回一个字符串数组,就是指定开启swagger的环境
boolean isEnable = environment.acceptsProfiles(of);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
// 通过 enable() 接收此参数判断是否要显示
.enable(isEnable)
.select()
.apis(RequestHandlerSelectors.basePackage("com.qk.controller"))
.paths(PathSelectors.ant("/hello/**"))
.build();
}
private ApiInfo apiInfo(){
return new ApiInfo("乾坤大挪移",
"Api Documentation by qk",
"9.9", "https://blog.csdn.net/qq_40429067",
new Contact("qk", "https://blog.csdn.net/qq_40429067", "[email protected]"),
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
}
swagger配置中,值的传递
配置API分组
1. 如果没有配置分组,默认是default。通过groupName()方法即可配置分组
2. 配置多个分组:在协同开发中,无论几个人,有多少个配置类,多少个Docket实例,都会被@Bean注入到容器中,在swagger中通过groupName进行分组
@Configuration
@EnableSwagger2
public class HelloSwagger {
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).groupName("default");
}
}
实体配置
- 实体类
public class User {
public String username;
public String password;
}
- controller接口
@GetMapping("/user")
public User user(){
return new User();
}
- 只要在接口中,返回值存在实体类,就会被扫描到swagger中
通过在实体类添加注解,提高swagger的models的可读性
- @ApiModel为类添加注释
- @ApiModelProperty为类属性添加注释
@ApiModel("用户实体类")
public class User {
@ApiModelProperty("用户名")
public String username;
@ApiModelProperty("密码")
public String password;
}
- 只要接口的返回值为实体,都会被映射到models中,@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的,与是否显示在models中无关
通过@ApiOperation注解为接口的方法添加注释
@RestController
public class MyController {
@ApiOperation("hello控制类")
@PostMapping("/t1")
public String test01(){
return "hello swagger";
}
@GetMapping("/user")
public User user(){
return new User();
}
}
通过@ApiParam注解为接口的方法参数添加注释
@GetMapping("/user")
public User user(@ApiParam("用户名") String username){
return new User();
}
在swagger中测试接口
- 没有参数的
@ApiOperation("hello控制类")
@PostMapping("/t1")
public String test01(){
return "hello swagger";
}
- 参数类型为实体的
@PostMapping("/user1")
public String test03(User user){
return user.getUsername()+"的swagger测试成功";
}
- 其他测试:非对象型参数的传递,后端和swagger始终为null,目前没有找到解决方法
@PostMapping("/user")
public String test02(@ApiParam("用户名") String username,@ApiParam("密码") String password){
System.out.println(username+"被成功接收");
return username+"的密码是"+password;
}
总结:
- 可以通过swagger给一些比较难理解的属性或者接口,增加注释信息
- 接口文档实时更新
- 可以在线测试
拓展:其他皮肤
导入不同的jar包实现不同的皮肤定义:
1、默认的 访问 http://localhost:8080/swagger-ui.html
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2、bootstrap-ui 访问 http://localhost:8080/doc.html
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.1</version>
</dependency>
3、Layui-ui 访问 http://localhost:8080/docs.html
<dependency>
<groupId>com.github.caspar-chen</groupId>
<artifactId>swagger-ui-layer</artifactId>
<version>1.1.3</version>
</dependency>
4、mg-ui 访问 http://localhost:8080/document.html
<dependency>
<groupId>com.zyplayer</groupId>
<artifactId>swagger-mg-ui</artifactId>
<version>1.0.6</version>
</dependency>