前言:目前互联网开发市场都流行前后台真正的分离,后台提供数据API接口,前台负责请求数据并渲染。那么我们程序猿们在编写接口的时候,最不方便之处就是写完接口后需要进行文档的编写以及接口的测试。今天就介绍一款将接口文档编写和测试合并一起的集大成者Swagger,也是目前很多企业再用的一个API管理工具。此DEMO的开发环境是:MAVEN + Spring Boot 2.1.0 + JDK8 + Swagger2.9.2
1、快速构建Spring Boot项目
在https://start.spring.io/中选...,然后选用Spring Boot2.1.0版本,Group是com.mage,Artifact是swagger_restful,Dependencies选择web,这样就能快速构建一个基于Spring Boot的web项目了。如下图:
2、使用IDEA打开项目
解压swagger_restful.zip,然后使用idea导入项目,并执行SwaggerRestfulApplication.java,不报错说明项目构建成功
3、pom导入swagger2的依赖jar包
<!-- 用于JSON API文档的生成-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!--用于文档界面展示-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
其中springfox-swagger2这个jar包是用于JSON API文档的生成,springfox-swagger-ui用于API文档界面生成,其他版本请参考:https://mvnrepository.com/art...://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui
5、编写测试的Controller和Model(TestController和Test)
编写一个Test的数据模型
package com.mage.swagger_restful.model;
public class Test {
private Integer id;
private String content;
private Integer isValid;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getIsValid() {
return isValid;
}
public void setIsValid(Integer isValid) {
this.isValid = isValid;
}
}
基于Restful规则,编写一组测试的API接口:
package com.mage.swagger_restful.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("test")
public class TestController {
@GetMapping("")
public String list() {
return "查询列表数据!";
}
@GetMapping("{id}")
public String find(@PathVariable Integer id) {
return String.format("根据主键查询数据: %d", id);
}
@PostMapping("")
public String add() {
return "插入数据!";
}
@PutMapping("{id}")
public String update(@PathVariable Integer id) {
return String.format("根据主键更新一条记录: %d", id);
}
@DeleteMapping("{id}")
public String delete(@PathVariable Integer id) {
return String.format("根据主键删除记录: %d", id);
}
}
因为接口是基于Restful(本文不讨论Restful的编写规范)编写,所以如果单纯利用浏览器输入是没法进行接口测试的,比如模拟post, put或者delete请求,这时要测试可以借助一些浏览器的插件比如postman或者rested等。这样我们还要额外去安装工具,显得比较麻烦,同时工作中写完接口后,一般还会编写接口文档,那么聪明的码农就想着能不能优化这个流程,让接口测试和接口文档编写变得简单快捷,于是乎,swagger应用而生。
6、代码中集成Swagger
a) 编写Swagger的配置类
package com.mage.swagger_restful.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@ConditionalOnExpression("${swagger.enable:true}")
public class SwaggerConfig {
@Bean
public Docket createDocket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder().title("码歌学院API")
.description("码歌学院相关接口API文档")
.version("1.0").build())
.select()
.apis(RequestHandlerSelectors.basePackage("com.mage"))
.paths(PathSelectors.any())
.build();
return docket;
}
}
其中@EnableSwagger2开启Swagger2功能,是swagger2的注解,@ConditionalOnExpression("${swagger.enable:true}")当配置文件中swagger.enable为true时才启用swagger2,是spring boot注解,方便区分不同环境下是否启用swagger2。
b) 修改application.properties
swagger.enable=true
c) 修改Test实体模型和TestController,添加Swagger对应注解
修改Test实体模型:
package com.mage.swagger_restful.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(description = "测试模型实体")
public class Test {
@ApiModelProperty(name = "id", value = "主键", hidden = true)
private Integer id;
@ApiModelProperty(name = "content", value = "测试内容")
private String content;
@ApiModelProperty(name = "isValid", value = "是否有效0=无效,1=有效", hidden = true)
private Integer isValid;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getIsValid() {
return isValid;
}
public void setIsValid(Integer isValid) {
this.isValid = isValid;
}
}
其中:
@ApiModel(description = "测试模型实体")作用在参数实体或者响应实体上,description代表描述信息;
@ApiModelProperty(name = "id", value = "主键", hidden = true)作用在实体属性上,标记属性名称和说明内容,name代表属性名称,value表示属性内容,hidden是否因此,默认是false。
修改TestController:
package com.mage.swagger_restful.controller;
import com.mage.swagger_restful.model.Test;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("test")
@Api(tags = "测试API接口")
public class TestController {
@GetMapping("")
@ApiOperation(value="获取列表数据", notes="获取列表下测试数据")
public String list() {
return "查询列表数据!";
}
@GetMapping("{id}")
@ApiOperation(value="获取ID数据", notes="根据ID获取某条测试数据")
@ApiImplicitParam(name = "id", value = "主键id", paramType = "path", required = true)
public String find(@PathVariable Integer id) {
return String.format("根据主键查询数据: %d", id);
}
@PostMapping("")
@ApiOperation(value="新增数据")
@ApiParam(name = "test", value = "添加的测试模型实体")
public String add(@RequestBody Test test) {
return "插入数据!";
}
@PutMapping("{id}")
@ApiOperation(value="更新数据", notes="根据ID更新测试数据")
@ApiImplicitParam(name = "id", value = "主键id", paramType = "path", required = true)
public String update(@PathVariable Integer id, @ApiParam(name = "test", value = "更新的测试模型实体") @RequestBody Test test) {
return String.format("根据主键更新一条记录: %d", id);
}
@DeleteMapping("{id}")
@ApiOperation(value="删除数据", notes="根据ID删除测试数据")
@ApiImplicitParam(name = "id", value = "主键id", paramType = "path", required = true)
public String delete(@PathVariable Integer id) {
return String.format("根据主键删除记录: %d", id);
}
}
其中:
@Api(tags = "测试API接口")标记controller类是做什么的,tags表示分类;
@ApiOperation(value="获取列表数据", notes="获取列表下测试数据")标记controller下的方法,表示这个接口是做什么的,value就是说明作用,notes详细说明;
@ApiImplicitParam(name = "id", value = "主键id", paramType = "path", required = true)标记参数,name是参数名,value是参数说明,paramType是参数类型:path(路径参数),query(查询参数), body(请求体参数),header(请求头参数),form(表单提交参数),require代表是否必填,默认是false
@ApiParam(name = "test", value = "更新的测试模型实体")跟@ApiImplicitParam类似,标记参数,不过不同的是:
- 对Servlets或者非 JAX-RS的环境,只能使用 ApiImplicitParam。
- 在使用上,ApiImplicitParam比ApiParam具有更少的代码侵入性,只要写在方法上就可以了,但是需要提供具体的属性才能配合swagger ui解析使用。
- ApiParam只需要较少的属性,与swagger ui配合更好。
7、浏览器输入地址:http://localhost:8080/swagger-ui.html
点开测试API接口就可以进行测试:
8、注意
如果采用swagger2.9.0时,会出现一个bug,比如我修改一下TestController里面的find方法
旧方法:
新方法:
这时如果启动,访问swagger ui时会出现一个bug:
这个是一个数据类型转化的错误,就是因为我设置了id为int类型,而swagger默认给的是空字符串,因此就提示错误,解决方案有两种,第一种就是不要写dataType,第二种就是升级swagger-annotations和models jar包:
a)排除已经依赖的swagger-annotations和models jar包
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
b) 引入新的jar包
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
这样也能完美解决!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。