前言:目前互联网开发市场都流行前后台真正的分离,后台提供数据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接口就可以进行测试:

测试API接口

8、注意

如果采用swagger2.9.0时,会出现一个bug,比如我修改一下TestController里面的find方法

旧方法:

旧方法

新方法:

新方法

这时如果启动,访问swagger ui时会出现一个bug:

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>

这样也能完美解决!


kl2422
326 声望2 粉丝

上善若水。水善利万物而不争,处众人之所恶,故几于道。居善地,心善渊,与善人,言善信,政善治,事善能,动善时。夫唯不争,故无尤。做好个程序员!