转载

快速入门 Swagger

摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/Swagger/

1. 概述

目前,大多数系统都采用前后端分离。在享受前后端分离的好处的同时,接口联调往往成为团队效率的瓶颈,甚至产生前后端的矛盾。简单归结来说,有几方面的原因:

  • 问题一,接口设计滞后。 后端团队往往不喜欢 API 接口设计先行,提前和前端沟通好接口。而在开发阶段的中后期,在后端提供 API 接口后,而这些接口和前端的预期有一些偏差,很容易就产生抱怨,特别是项目周期比较紧张的情况下。
  • 问题二,接口不规范。 当团队里没有同意明确的接口规范时,又或者代码 Review 做的不是很好的情况下,千奇百怪、各式各样的 API 接口可能就产生了。前端在对接这样的 API 接口,苦不堪言,在一口 mmp 一嘴 fuck xxx 之中,调完接口。
  • 问题三,接口文档更新不及时,或者遗忘更新。 因为后端 API 代码和 API 接口在两个地方,我们无法保证提交 API 代码的同时,及时更新文档。有的时候,我们甚至会遗忘更新 API 接口。随着时间的流逝,API 文档和 API 接口不一致的地方越来越多,前端会对 API 接口的信任度越来越低,然后不知道不觉之中,回到原始时代,直接问后端开发 API 是什么样的。

对于问题一问题二,更多是开发流程上的问题,所以不在本文的范围内,还是要给点粗浅的建议,完全拦不住我啊。

  • 接口设计先行。设计完成后,后端和前端进行简单沟通,看看是否能够满足诉求。
  • 统一的接口规范。一定要制定统一的接口规范文档,即使比较简陋,也能保证团队的 API 接口相对统一一致。? 即使错,咱也错的一模一样,而不是千奇百怪。当然,接口规范是无法覆盖到所有的场景的,借助于“接口设计先行”,我们可以提前去 Review 每个接口的设计。

对于问题三,就进入了本文的主角 Swagger 。通过在 API 接口上,添加相应的 Swagger 提供的注解,自动生成 API 文档。酱紫,API 接口和文档就在一起了,从此过上了幸福快乐的生活。

FROM 《RESTful 风格的 Web 服务框架 Swagger》

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。

总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。

2. 快速入门 Swagger

示例代码对应仓库:lab-24-apidoc-swagger

在本小节,我们来快速入门 Swagger ,可以更加直观的感受到其提供的便利性。

2.1 引入依赖

pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-24-apidoc-swagger</artifactId>

    <dependencies>
        <!-- 实现对 Spring MVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入 Swagger 依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- 引入 Swagger UI 依赖,以实现 API 接口的 UI 界面 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

    </dependencies>

</project>

2.2 SwaggerConfiguration

因为 Spring Boot 暂未提供 Swagger 内置的支持,所以我们需要自己定义配置类。

cn.iocoder.springboot.lab24.apidoc.config 包路径下,创建 SwaggerConfiguration 配置类,用于配置 Swagger 。代码如下:

// SwaggerConfiguration.java

@Configuration
@EnableSwagger2 // 标记项目启用 Swagger API 接口文档
public class SwaggerConfiguration {

    @Bean
    public Docket createRestApi() {
        // 创建 Docket 对象
        return new Docket(DocumentationType.SWAGGER_2) // 文档类型,使用 Swagger2
                .apiInfo(this.apiInfo()) // 设置 API 信息
                // 扫描 Controller 包路径,获得 API 接口
                .select()
                .apis(RequestHandlerSelectors.basePackage("cn.iocoder.springboot.lab24.apidoc.controller"))
                .paths(PathSelectors.any())
                // 构建出 Docket 对象
                .build();
    }

    /**
     * 创建 API 信息
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("测试接口文档示例")
                .description("我是一段描述")
                .version("1.0.0") // 版本号
                .contact(new Contact("sakura", "http://sakurac.cn", "kinomotosakuraping@gmail.com")) // 联系人
                .build();
    }

}
  • 在类上,添加 @EnableSwagger2 注解, 标记项目启用 Swagger API 接口文档。
  • 通过**#createRestApi()**方法,创建 Swagger Docket Bean 。每个属性的作用。大多数情况下,使用这些属性是足够的。不过如果想看看其它配置,可以自己去如下两个类翻翻:

2.3 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

先暂时不启动项目。等我们添加好 Controller 。

2.4 UserController

cn.iocoder.springboot.lab24.apidoc.controller 包路径下,创建 UserController 类,提供用户 API 接口。代码如下:

// UserController.java

@RestController
@RequestMapping("/users")
@Api(tags = "用户 API 接口")
public class UserController {

    @GetMapping("/list")
    @ApiOperation(value = "查询用户列表", notes = "目前仅仅是作为测试,所以返回用户全列表")
    public List<UserVO> list() {
        // 查询列表
        List<UserVO> result = new ArrayList<>();
        result.add(new UserVO().setId(1).setUsername("yudaoyuanma"));
        result.add(new UserVO().setId(2).setUsername("woshiyutou"));
        result.add(new UserVO().setId(3).setUsername("chifanshuijiao"));
        // 返回列表
        return result;
    }

    @GetMapping("/get")
    @ApiOperation("获得指定用户编号的用户")
    @ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024")
    public UserVO get(@RequestParam("id") Integer id) {
        // 查询并返回用户
        return new UserVO().setId(id).setUsername(UUID.randomUUID().toString());
    }

    @PostMapping("add")
    @ApiOperation("添加用户")
    public Integer add(UserAddDTO addDTO) {
        // 插入用户记录,返回编号
        Integer returnId = UUID.randomUUID().hashCode();
        // 返回用户编号
        return returnId;
    }

    @PostMapping("/update")
    @ApiOperation("更新指定用户编号的用户")
    public Boolean update(UserUpdateDTO updateDTO) {
        // 更新用户记录
        Boolean success = true;
        // 返回更新是否成功
        return success;
    }

    @PostMapping("/delete")
    @ApiOperation(value = "删除指定用户编号的用户")
    @ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024")
    public Boolean delete(@RequestParam("id") Integer id) {
        // 删除用户记录
        Boolean success = false;
        // 返回是否更新成功
        return success;
    }

}
  • 相比我们之前使用 SpringMVC 来说,我们在类和接口上,额外增加了 Swagger 提供的注解。
  • 从使用习惯上,我比较喜欢先添加 SpringMVC 的注解,再添加 Swagger 的注解。
  • 因为已经使用了 Swagger 的注解,所以类和方法上的注释,一般可以删除了,除非有特殊诉求。
  • 其中涉及到的 POJO 类,有 UserAddDTOUserUpdateDTOUserVO

执行 Application 启动项目。然后浏览器访问 http://127.0.0.1:8080/swagger-ui.html 地址,就可以看到 Swagger 生成的 API 接口文档。如下图所示:

至此,我们已经完成了 Swagger 的快速入门。不过考虑到能够更好的使用,我们来一个一个注解了解。

如果启动遇到报错,可以在yml文件下添加以下配置

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

2.5 注解

swagger-annotations 库中,在 io.swagger.annotations 包路径下,提供了我们会使用到的所有 Swagger 注解。Swagger 提供的注解还是比较多的,大多数场景下,只需要使用到我们在 「2.4 UserController」 中用到的注解。

2.5.1 @Api

@Api 注解,添加在 Controller 类上,标记它作为 Swagger 文档资源。

示例如下:

// UserController.java

@RestController
@RequestMapping("/users")
@Api(tags = "用户 API 接口")
public class UserController {

    // ... 省略
}

效果如下:

@Api 注解的常用属性,如下:

  • tags 属性:用于控制 API 所属的标签列表。[]数组,可以填写多个。
  • 可以在一个 Controller 上的 @Apitags 属性,设置多个标签,那么这个 Controller 下的 API 接口,就会出现在这两个标签中。
    • 如果在多个 Controller 上的 @Apitags 属性,设置一个标签,那么这些 Controller 下的 API 接口,仅会出现在这一个标签中。
  • 本质上,tags 就是为了分组 API 接口,和 Controller 本质上是一个目的。所以绝大数场景下,我们只会给一个 Controller 一个唯一的标签。例如说,UserController 的 tags 设置为 "用户 API 接口"

@Api 注解的不常用属性,如下:

  • produces 属性:请求请求头的可接受类型( Accept )。如果有多个,使用 , 分隔。
  • consumes 属性:请求请求头的提交内容类型( Content-Type )。如果有多个,使用 , 分隔。
  • protocols 属性:协议,可选值为 "http""https""ws""wss" 。如果有多个,使用 , 分隔。
  • authorizations 属性:授权相关的配置,[] 数组,使用 @Authorization 注解。
  • hidden 属性:是否隐藏,不再 API 接口文档中显示。

@Api 注解的废弃属性,不建议使用,有 valuedescriptionbasePathposition

2.5.2 @ApiOperation

@ApiOperation 注解,添加在 Controller 方法上,标记它是一个 API 操作。

示例如下:

// UserController.java

@GetMapping("/list")
@ApiOperation(value = "查询用户列表", notes = "目前仅仅是作为测试,所以返回用户全列表")
public List<UserVO> list() {
    // 查询列表
    List<UserVO> result = new ArrayList<>();
    result.add(new UserVO().setId(1).setUsername("yudaoyuanma"));
    result.add(new UserVO().setId(2).setUsername("woshiyutou"));
    result.add(new UserVO().setId(3).setUsername("chifanshuijiao"));
    // 返回列表
    return result;
}

效果如下:

@ApiOperation 注解的常用属性,如下:

  • value 属性:API 操作名。
  • notes 属性:API 操作的描述。

@ApiOperation 注解的不常用属性,如下:

  • tags 属性:和 @API 注解的 tags 属性一致。
  • nickname 属性:API 操作接口的唯一标识,主要用于和第三方工具做对接。
  • httpMethod 属性:请求方法,可选值为 GETHEADPOSTPUTDELETEOPTIONSPATCH 。因为 Swagger 会解析 SpringMVC 的注解,所以一般无需填写。
  • produces 属性:和 @API 注解的 produces 属性一致。
  • consumes 属性:和 @API 注解的 consumes 属性一致。
  • protocols 属性:和 @API 注解的 protocols 属性一致。
  • authorizations 属性:和 @API 注解的 authorizations 属性一致。
  • hidden 属性:和 @API 注解的 hidden 属性一致。
  • response 属性:响应结果类型。因为 Swagger 会解析方法的返回类型,所以一般无需填写。
  • responseContainer 属性:响应结果的容器,可选值为 ListSetMap
  • responseReference 属性:指定对响应类型的引用。这个引用可以是本地,也可以是远程。并且,当设置了它时,会覆盖 response 属性。说人话,就是可以忽略这个属性,哈哈哈。
  • responseHeaders 属性:响应头,[] 数组,使用 @ResponseHeader 注解。
  • code 属性:响应状态码,默认为 200 。
  • extensions 属性:拓展属性,[] 属性,使用 @Extension 注解。
  • ignoreJsonView 属性:在解析操作和类型,忽略 JsonView 注释。主要是为了向后兼容。

@ApiOperation 注解的废弃属性,不建议使用,有 position

2.5.3 @ApiImplicitParam

@ApiImplicitParam 注解,添加在 Controller 方法上,声明每个请求参数的信息。

示例如下:

// UserController.java

@PostMapping("/delete")
@ApiOperation(value = "删除指定用户编号的用户")
@ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024")
public Boolean delete(@RequestParam("id") Integer id) {
    // 删除用户记录
    Boolean success = false;
    // 返回是否更新成功
    return success;
}

效果如下:

@ApiImplicitParam 注解的常用属性,如下:

  • name 属性:参数名。

  • value 属性:参数的简要说明。

  • required 属性:是否为必传参数。默认为 false

  • dataType 属性:数据类型,通过字符串 String 定义。

  • dataTypeClass 属性:数据类型,通过 dataTypeClass 定义。在设置了 dataTypeClass 属性的情况下,会覆盖 dataType 属性。推荐采用这个方式

  • paramType

    属性:参数所在位置的类型。有如下 5 种方式:

    • "path" 值:对应 SpringMVC 的 @PathVariable 注解。
    • 默认值"query" 值:对应 SpringMVC 的 @PathVariable 注解。
    • "body" 值:对应 SpringMVC 的 @RequestBody 注解。
    • "header" 值:对应 SpringMVC 的 @RequestHeader 注解。
    • "form" 值:Form 表单提交,对应 SpringMVC 的 @PathVariable 注解。
    • ? 绝大多数情况下,使用 "query" 值这个类型即可。
  • example 属性:参数值的简单示例。

  • examples 属性:参数值的复杂示例,使用 @Example 注解。

@ApiImplicitParam 注解的不常用属性,如下:

  • defaultValue 属性:默认值。

  • allowableValues

    属性:允许的值。如果要设置多个值,有两种方式:

    • 数组方式,即 {value1, value2, value3} 。例如说,{1, 2, 3}
    • 范围方式,即 [value1, value2][value1, value2) 。例如说 [1, 5] 表示 1 到 5 的所有数字。如果有无穷的,可以使用 (-infinity, value2][value1, infinity)
  • allowEmptyValue 属性:是否允许空值。

  • allowMultiple 属性:是否允许通过多次传递该参数来接受多个值。默认为 false

  • type 属性:搞不懂具体用途,对应英文注释为 Adds the ability to override the detected type

  • readOnly 属性:是否只读。

  • format 属性:自定义的格式化。

  • collectionFormat 属性:针对 Collection 集合的,自定义的格式化。

当我们需要添加在方法上添加多个 @ApiImplicitParam 注解时,可以使用 @ApiImplicitParams 注解中添加多个。示例如下:

@ApiImplicitParams({ // 参数数组
        @ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024"), // 参数一
        @ApiImplicitParam(name = "name", value = "昵称", paramType = "query", dataTypeClass = String.class, required = true, example = "芋道"), // 参数二
})

2.5.4 @ApiModel

@ApiModel 注解,添加在 POJO 类,声明 POJO 类的信息。而在 Swagger 中,把这种 POJO 类称为 Model 类。所以,我们下文就统一这么称呼。

示例如下:

// UserVO.java

@ApiModel("用户 VO")
public class UserVO {

    // ... 省略

}

效果如下:

@ApiModel 注解的常用属性,如下:

  • value 属性:Model 名字。
  • description 属性:Model 描述。

@ApiModel 注解的不常用属性,如下:

  • parent 属性:指定该 Model 的父 Class 类,用于继承父 Class 的 Swagger 信息。
  • subTypes 属性:定义该 Model 类的子类 Class 们。
  • discriminator 属性:搞不懂具体用途,对应英文注释为 Supports model inheritance and polymorphism.
  • reference 属性:搞不懂具体用途,对应英文注释为 Specifies a reference to the corresponding type definition, overrides any other metadata specified

2.5.5 @ApiModelProperty

@ApiModelProperty 注解,添加在 Model 类的成员变量上,声明每个成员变量的信息。

示例如下:

// UserVO.java

@ApiModel("用户 VO")
public class UserVO {

    @ApiModelProperty(value = "用户编号", required = true, example = "1024")
    private Integer id;
    @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma")
    private String username;

    // ... 省略 set/get 方法
}

效果如下:

@ApiModelProperty 注解的常用属性,如下:

  • value 属性:属性的描述。
  • dataType 属性:和 @ApiImplicitParam 注解的 dataType 属性一致。不过因为 @ApiModelProperty 是添加在成员变量上,可以自动获得成员变量的类型。
  • required 属性:和 @ApiImplicitParam 注解的 required 属性一致。
  • example 属性:@ApiImplicitParam 注解的 example 属性一致。

@ApiModelProperty 注解的不常用属性,如下:

  • name 属性:覆盖成员变量的名字,使用该属性进行自定义。
  • allowableValues 属性:和 @ApiImplicitParam 注解的 allowableValues 属性一致。
  • position 属性:成员变量排序位置,默认为 0 。
  • hidden 属性:@ApiImplicitParam 注解的 hidden 属性一致。
  • accessMode 属性:访问模式,有 AccessMode.AUTOAccessMode.READ_ONLYAccessMode.READ_WRITE 三种,默认为 AccessMode.AUTO
  • reference 属性:和 @ApiModel 注解的 reference 属性一致。
  • allowEmptyValue 属性:和 @ApiImplicitParam 注解的 allowEmptyValue 属性一致。
  • extensions 属性:和 @ApiImplicitParam 注解的 extensions 属性一致。

@ApiModelProperty 注解的废弃属性,不建议使用,有 readOnly

2.5.6 @ApiResponse

在大多数情况下,我们并不需要使用 @ApiResponse 注解,因为我们会类似 UserController#get(id) 方法这个接口,返回一个 Model 即可。所以 @ApiResponse 注解,艿艿就简单讲解,嘿嘿。

@ApiResponse 注解,添加在 Controller 类的方法上,声明每个响应参数的信息。

@ApiResponse 注解的属性,基本已经被 @ApiOperation 注解所覆盖,如下:

  • message 属性:响应的提示内容。
  • code 属性:和 @ApiOperation 注解的 code 属性一致。
  • response 属性:和 @ApiOperation 注解的 response 属性一致。
  • reference 属性:和 @ApiOperation 注解的 responseReference 属性一致。
  • responseHeaders 属性:和 @ApiOperation 注解的 responseHeaders 属性一致。
  • responseContainer 属性:和 @ApiOperation 注解的 responseContainer 属性一致。
  • examples 属性:和 @ApiOperation 注解的 examples 属性一致。

当我们需要添加在方法上添加多个 @ApiResponse 注解时,可以使用 @ApiResponses 注解中添加多个。

至此,我们已经了解完 Swagger 项目中提供的主要注解。如果想要看到更多的 Swagger 的使用示例,可以看看艿艿开源的 onemall 项目。

咳咳咳,整理 Swagger 注解的每个属性,真的是花费时间。如果有哪个解释不到位,请一定给艿艿留言,我去优化和调整下,嘻嘻。

2.6 测试接口

在 Swagger 的 UI 界面上,提供了简单的测试接口的工具。我们仅仅需要点开某个接口,点击「Try it out」按钮。如下图:

然后,点击「Execute」按钮,即可执行一次 API 接口的调用。如下图:

在三个红圈中,我们可以看到 Swagger 给我们提供了:

  • 提供了 curl 命令,让我们可以直接在命令行执行。
  • 提供了 Request URL 地址,方便我们在浏览器中访问。
  • 提供了执行结果,我们可以人肉看看,是否符合我们希望的结果。

3. 更好看的 Swagger UI 界面

示例代码对应仓库:lab-24-apidoc-swagger-knife4j

springfox-swagger-ui 提供的 UI 界面,基本能够满足我们的日常使用,但是距离好用,还是有一段距离。幸福的是,社区有人开源了 swagger-bootstrap-ui 项目,提供更好看且好用的 UI 界面。

具体的演示示例,可以访问:http://swagger-bootstrap-ui.xiaominfo.com/doc.html 查看。

「2. 快速入门 Swagger」lab-24-apidoc-swagger 示例的基础上,我们复制出 lab-24-apidoc-swagger-knife4j 项目,进行改造。

3.1 修改依赖

pom.xml 文件中,修改相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-24-apidoc-swagger-knife4j</artifactId>

    <dependencies>
        <!-- 实现对 Spring MVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 1. swagger-bootstrap-ui 目前改名为 knife4j -->
        <!-- 2. 实现 swagger-bootstrap-ui 的自动化配置  -->
        <!-- 3. 因为 knife4j-spring 已经引入 Swagger 依赖,所以无需重复引入 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-ui</artifactId>
            <version>1.9.6</version>
        </dependency>

    </dependencies>

</project>

3.2 界面一览

直接使用 Application 启动项目,无需做其它任何的变更,方便的说。

浏览器访问 http://localhost:8080/doc.html 地址,就可以看到 的 Swagger 生成的 API 接口文档。

更多功能,可以看 官方文档 ,非常推荐生产中。

  • 作者:管理员(联系作者)
  • 发表时间:2022-09-02 18:08
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论