之前通过Spring Boot 2.x基础教程:使用Swagger2构建强大的API文档一文,我们学习了如何使用Swagger为Spring Boot项目自动生成API文档,有不少用户留言问了关于文档内容的组织以及排序问题。所以,就特别开一篇详细说说Swagger中文档内容如何来组织以及其中各个元素如何控制前后顺序的具体配置方法。

接口的分组

我们在Spring Boot中定义各个接口是以Controller作为第一级维度来进行组织的,Controller与具体接口之间的关系是一对多的关系。我们可以将同属一个模块的接口定义在一个Controller里。默认情况下,Swagger是以Controller为单位,对接口进行分组管理的。这个分组的元素在Swagger中称为Tag,但是这里的Tag与接口的关系并不是一对多的,它支持更丰富的多对多关系。

默认分组

首先,我们通过一个简单的例子,来看一下默认情况,Swagger是如何根据Controller来组织Tag与接口关系的。定义两个Controller,分别负责教师管理与学生管理接口,比如下面这样:

@RestController
@RequestMapping(value = "/teacher")
static class TeacherController { @GetMapping("/xxx")
public String xxx() {
return "xxx";
} } @RestController
@RequestMapping(value = "/student")
static class StudentController { @ApiOperation("获取学生清单")
@GetMapping("/list")
public String bbb() {
return "bbb";
} @ApiOperation("获取教某个学生的老师清单")
@GetMapping("/his-teachers")
public String ccc() {
return "ccc";
} @ApiOperation("创建一个学生")
@PostMapping("/aaa")
public String aaa() {
return "aaa";
} }

启动应用之后,我们可以看到Swagger中这两个Controller是这样组织的:

图中标出了Swagger默认生成的Tag与Spring Boot中Controller展示的内容与位置。

自定义默认分组的名称

接着,我们可以再试一下,通过@Api注解来自定义Tag,比如这样:

@Api(tags = "教师管理")
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController { // ... } @Api(tags = "学生管理")
@RestController
@RequestMapping(value = "/student")
static class StudentController { // ... }

再次启动应用之后,我们就看到了如下的分组内容,代码中@Api定义的tags内容替代了默认产生的teacher-controllerstudent-controller

合并Controller分组

到这里,我们还都只是使用了TagController一一对应的情况,Swagger中还支持更灵活的分组!从@Api注解的属性中,相信聪明的读者一定已经发现tags属性其实是个数组类型:

我们可以通过定义同名的Tag来汇总Controller中的接口,比如我们可以定义一个Tag为“教学管理”,让这个分组同时包含教师管理和学生管理的所有接口,可以这样来实现:

@Api(tags = {"教师管理", "教学管理"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController { // ... } @Api(tags = {"学生管理", "教学管理"})
@RestController
@RequestMapping(value = "/student")
static class StudentController { // ... }

最终效果如下:

更细粒度的接口分组

通过@Api可以实现将Controller中的接口合并到一个Tag中,但是如果我们希望精确到某个接口的合并呢?比如这样的需求:“教学管理”包含“教师管理”中所有接口以及“学生管理”管理中的“获取学生清单”接口(不是全部接口)。

那么上面的实现方式就无法满足了。这时候发,我们可以通过使用@ApiOperation注解中的tags属性做更细粒度的接口分类定义,比如上面的需求就可以这样子写:

@Api(tags = {"教师管理","教学管理"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController { @ApiOperation(value = "xxx")
@GetMapping("/xxx")
public String xxx() {
return "xxx";
} } @Api(tags = {"学生管理"})
@RestController
@RequestMapping(value = "/student")
static class StudentController { @ApiOperation(value = "获取学生清单", tags = "教学管理")
@GetMapping("/list")
public String bbb() {
return "bbb";
} @ApiOperation("获取教某个学生的老师清单")
@GetMapping("/his-teachers")
public String ccc() {
return "ccc";
} @ApiOperation("创建一个学生")
@PostMapping("/aaa")
public String aaa() {
return "aaa";
} }

效果如下图所示:

内容的顺序

在完成了接口分组之后,对于接口内容的展现顺序又是众多用户特别关注的点,其中主要涉及三个方面:分组的排序、接口的排序以及参数的排序,下面我们就来逐个说说如何配置与使用。

分组的排序

关于分组排序,也就是Tag的排序。目前版本的Swagger支持并不太好,通过文档我们可以找到关于Tag排序的配置方法。

第一种:原生Swagger用户,可以通过如下方式:

第二种:Swagger Starter用户,可以通过修改配置的方式:

swagger.ui-config.tags-sorter=alpha

似乎找到了希望,但是其实这块并没有什么可选项,一看源码便知:

public enum TagsSorter {
ALPHA("alpha"); private final String value; TagsSorter(String value) {
this.value = value;
} @JsonValue
public String getValue() {
return value;
} public static TagsSorter of(String name) {
for (TagsSorter tagsSorter : TagsSorter.values()) {
if (tagsSorter.value.equals(name)) {
return tagsSorter;
}
}
return null;
}
}

是的,Swagger只提供了一个选项,就是按字母顺序排列。那么我们要如何实现排序呢?这里笔者给一个不需要扩展源码,仅依靠使用方式的定义来实现排序的建议:为Tag的命名做编号。比如:

@Api(tags = {"1-教师管理","3-教学管理"})
@RestController
@RequestMapping(value = "/teacher")
static class TeacherController { // ... } @Api(tags = {"2-学生管理"})
@RestController
@RequestMapping(value = "/student")
static class StudentController { @ApiOperation(value = "获取学生清单", tags = "3-教学管理")
@GetMapping("/list")
public String bbb() {
return "bbb";
} // ... }

由于原本存在按字母排序的机制在,通过命名中增加数字来帮助排序,可以简单而粗暴的解决分组问题,最后效果如下:

接口的排序

在完成了分组排序问题(虽然不太优雅...)之后,在来看看同一分组内各个接口该如何实现排序。同样的,凡事先查文档,可以看到Swagger也提供了相应的配置,下面也分两种配置方式介绍:

第一种:原生Swagger用户,可以通过如下方式:

第二种:Swagger Starter用户,可以通过修改配置的方式:

swagger.ui-config.operations-sorter=alpha

很庆幸,这个配置不像Tag的排序配置没有可选项。它提供了两个配置项:alphamethod,分别代表了按字母表排序以及按方法定义顺序排序。当我们不配置的时候,改配置默认为alpha。两种配置的效果对比如下图所示:

参数的排序

完成了接口的排序之后,更细粒度的就是请求参数的排序了。默认情况下,Swagger对Model参数内容的展现也是按字母顺序排列的。所以之前教程中的User对象在文章中展现如下:

如果我们希望可以按照Model中定义的成员变量顺序来展现,那么需要我们通过@ApiModelProperty注解的position参数来实现位置的设置,比如:

@Data
@ApiModel(description = "用户实体")
public class User { @ApiModelProperty(value = "用户编号", position = 1)
private Long id; @NotNull
@Size(min = 2, max = 5)
@ApiModelProperty(value = "用户姓名", position = 2)
private String name; @NotNull
@Max(100)
@Min(10)
@ApiModelProperty(value = "用户年龄", position = 3)
private Integer age; @NotNull
@Email
@ApiModelProperty(value = "用户邮箱", position = 4)
private String email; }

最终效果如下:

小结

本文详细的介绍了Swagger中对接口内容的组织控制。有些问题并没有通过配置来解决,也可能是对文档或源码内容的了解不够深入。如果读者有更好的实现方案,欢迎提出与交流。

代码示例

本文的完整工程可以查看下面仓库中的chapter2-4目录:

如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力!

相关资料

欢迎关注我的公众号:程序猿DD,获得独家整理的学习资源和日常干货推送。

如果您对我的专题内容感兴趣,也可以关注我的博客:didispace.com

Spring Boot 2.x基础教程:Swagger接口分类与各元素排序问题详解的更多相关文章

  1. Spring Boot 2.x基础教程:Swagger静态文档的生成

    前言 通过之前的两篇关于Swagger入门以及具体使用细节的介绍之后,我们已经能够轻松地为Spring MVC的Web项目自动构建出API文档了.如果您还不熟悉这块,可以先阅读: Spring Boo ...

  2. Spring Boot 2.x基础教程:使用Swagger2构建强大的API文档

    随着前后端分离架构和微服务架构的流行,我们使用Spring Boot来构建RESTful API项目的场景越来越多.通常我们的一个RESTful API就有可能要服务于多个不同的开发人员或开发团队:I ...

  3. Spring Boot 2.x基础教程:JSR-303实现请求参数校验

    请求参数的校验是很多新手开发非常容易犯错,或存在较多改进点的常见场景.比较常见的问题主要表现在以下几个方面: 仅依靠前端框架解决参数校验,缺失服务端的校验.这种情况常见于需要同时开发前后端的时候,虽然 ...

  4. Spring Boot 2.x基础教程:使用国产数据库连接池Druid

    上一节,我们介绍了Spring Boot在JDBC模块中自动化配置使用的默认数据源HikariCP.接下来这一节,我们将介绍另外一个被广泛应用的开源数据源:Druid. Druid是由阿里巴巴数据库事 ...

  5. Spring Boot 2.x基础教程:找回启动日志中的请求路径列表

    如果您看过之前的Spring Boot 1.x教程,或者自己原本就对Spring Boot有一些经验,或者对Spring MVC很熟悉.那么对于Spring构建的Web应用在启动的时候,都会输出当前应 ...

  6. Spring Boot 2.x基础教程:事务管理入门

    什么是事务? 我们在开发企业应用时,通常业务人员的一个操作实际上是对数据库读写的多步操作的结合.由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻 ...

  7. Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

  8. Spring Boot 2.x基础教程:使用EhCache缓存集群

    上一篇我们介绍了在Spring Boot中整合EhCache的方法.既然用了ehcache,我们自然要说说它的一些高级功能,不然我们用默认的ConcurrentHashMap就好了.本篇不具体介绍Eh ...

  9. Spring Boot 2.x基础教程:如何扩展XML格式的请求和响应

    在之前的所有Spring Boot教程中,我们都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式 ...

随机推荐

  1. 检查python标识符是否有效

  2. 2018 Petrozavodsk Winter Camp, Yandex Cup

    A. Ability Draft solved by RDC 60min start, 148 min AC, 1Y 题意:两只 Dota 队伍,每队 \(n\) 个英雄,英雄一开始无技能,他们需要按 ...

  3. CodeForces 812E Sagheer and Apple Tree 树上nim

    Sagheer and Apple Tree 题解: 先分析一下, 如果只看叶子层的话. 那么就相当于 经典的石子问题 nim 博弈了. 那我们看非叶子层. 看叶子层的父亲层. 我们可以发现, 如果从 ...

  4. 牛客小白月赛6 A 鲲 数学

    链接:https://www.nowcoder.com/acm/contest/136/A来源:牛客网 北冥有鱼,其名为鲲,鲲之大,不知其几千里也. ——<庄子·逍遥游> HtBest有一 ...

  5. 【Spring】 AOP Base

    1. AOP概述 2. AOP的术语: 3. AOP底层原理 4. Spring 中的AOP 4.1 概述 4.2 分类 4.3 Spring的传统AOP 针对所有方法的增强:(不带有切点的切面) 带 ...

  6. Django + Gunicorn + Nginx 部署之路

    前言 最近,我已经成功将我的个人网站从 Flask 迁移到 Django 了,最早接触 Django 的时候大概是在 4 年前,我记得那个时候 Django 中的路由配置使用 正则 来进行的,但是我有 ...

  7. Redis真的那么好用吗

    Redis是什么 Redis是一个开源的底层使用C语言编写的key-value存储数据库.可用于缓存.事件发布订阅.高速队列等场景.而且支持丰富的数据类型:string(字符串).hash(哈希).l ...

  8. java多线程之创建线程的4种方式及Future

    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例.Java可以用四种方式来创建线程: 继承Thread创建线程 实现Runnable接口创建线程 实现callab ...

  9. Spring Cloud官方文档中文版-服务发现:Eureka客户端

    官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_spring_cloud_netflix 文中例子我做了一些测试在:h ...

  10. Net基础篇_学习笔记_第十一天_面向对象(练习)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...