Spring Boot 2.x 基础教程:使用 Swagger2 构建强大的 API 文档 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dyc87112
V2EX    Java

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

  •  
  •   dyc87112
    dyc87112 2019-10-14 12:25:13 +08:00 3682 次点击
    这是一个创建于 2187 天前的主题,其中的息可能已经有所发展或是发生改变。

    随着前后端分离架构和微服务架构的流行,我们使用 Spring Boot 来构建 RESTful API 项目的场景越来越多。通常我们的一个 RESTful API 就有可能要服务于多个不同的开发人员或开发团队:IOS 开发、Android 开发、Web 开发甚至其他的后端服务等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法就是创建一份 RESTful API 文档来记录所有接口细节,然而这样的做法有以下几个问题:

    • 由于接口众多,并且细节复杂(需要考虑不同的 HTTP 请求类型、HTTP 头部信息、HTTP 请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。
    • 随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。

    为了解决上面这样的问题,本文将介绍 RESTful API 的重磅好伙伴 Swagger2,它可以轻松的整合到 Spring Boot 中,并与 Spring MVC 程序配合组织出强大 RESTful API 文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外 Swagger2 也提供了强大的页面测试功能来调试每个 RESTful API。具体效果如下图所示:

    下面来具体介绍,在 Spring Boot 中使用我们自己实现的 starter 来整合 Swagger。该整合项目的 Github:https://github.com/SpringForAll/spring-boot-starter-swagger。如果您觉得它好用,欢迎 Star 支持我们!

    准备工作

    首先,我们需要一个 Spring Boot 实现的 RESTful API 工程,若您没有做过这类内容,建议先阅读上一篇教程: Spring Boot 2.x 基础教程:构建 RESTful API 与单元测试构建一个。或者也可以直接使用上一篇教程中的样例作为基础,即下面仓库中的chapter2-1工程:

    整合 Swagger2

    下面,我们以上面仓库中的chapter2-1工程进行整合改造。

    第一步:添加 swagger-spring-boot-starter 依赖

    pom.xml中加入依赖,具体如下:

    <dependency> <groupId>com.spring4all</groupId> <artifactId>swagger-spring-boot-starter</artifactId> <version>1.9.0.RELEASE</version> </dependency> 

    第二步:应用主类中添加@EnableSwagger2Doc注解,具体如下

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

    第三步application.properties中配置文档相关内容,比如

    swagger.title=spring-boot-starter-swagger swagger.description=Starter for swagger 2.x swagger.version=1.4.0.RELEASE swagger.license=Apache License, Version 2.0 swagger.licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.html swagger.termsOfServiceUrl=https://github.com/dyc87112/spring-boot-starter-swagger swagger.contact.name=didi swagger.contact.url=http://blog.didispace.com [email protected] swagger.base-package=com.didispace swagger.base-path=/** 

    各参数配置含义如下:

    • swagger.title:标题
    • swagger.description:描述
    • swagger.version:版本
    • swagger.license:许可证
    • swagger.licenseUrl:许可证 URL
    • swagger.termsOfServiceUrl:服务条款 URL
    • swagger.contact.name:维护人
    • swagger.contact.url:维护人 URL
    • swagger.contact.email:维护人 email
    • swagger.base-package:swagger 扫描的基础包,默认:全扫描
    • swagger.base-path:需要处理的基础 URL 规则,默认:/**

    更多配置说明可见官方说明:https://github.com/SpringForAll/spring-boot-starter-swagger

    第四步:启动应用,访问:http://localhost:8080/swagger-ui.html,就可以看到如下的接口文档页面:

    添加文档内容

    在整合完 Swagger 之后,在http://localhost:8080/swagger-ui.html页面中可以看到,关于各个接口的描述还都是英文或遵循代码定义的名称产生的。这些内容对用户并不友好,所以我们需要自己增加一些说明来丰富文档内容。如下所示,我们通过@Api@ApiOperation注解来给 API 增加说明、通过@ApiImplicitParam@ApiModel@ApiModelProperty注解来给参数增加说明。

    比如下面的例子:

    @Api(tags = "用户管理") @RestController @RequestMapping(value = "/users") // 通过这里配置使下面的映射都在 /users 下 public class UserController { // 创建线程安全的 Map,模拟 users 信息的存储 static Map<Long, User> users = Collections.synchronizedMap(new HashMap<>()); @GetMapping("/") @ApiOperation(value = "获取用户列表") public List<User> getUserList() { List<User> r = new ArrayList<>(users.values()); return r; } @PostMapping("/") @ApiOperation(value = "创建用户", notes = "根据 User 对象创建用户") public String postUser(@RequestBody User user) { users.put(user.getId(), user); return "success"; } @GetMapping("/{id}") @ApiOperation(value = "获取用户详细信息", notes = "根据 url 的 id 来获取用户详细信息") public User getUser(@PathVariable Long id) { return users.get(id); } @PutMapping("/{id}") @ApiImplicitParam(paramType = "path", dataType = "Long", name = "id", value = "用户编号", required = true, example = "1") @ApiOperation(value = "更新用户详细信息", notes = "根据 url 的 id 来指定更新对象,并根据传过来的 user 信息来更新用户详细信息") public String putUser(@PathVariable Long id, @RequestBody User user) { User u = users.get(id); u.setName(user.getName()); u.setAge(user.getAge()); users.put(id, u); return "success"; } @DeleteMapping("/{id}") @ApiOperation(value = "删除用户", notes = "根据 url 的 id 来指定删除对象") public String deleteUser(@PathVariable Long id) { users.remove(id); return "success"; } } @Data @ApiModel(description="用户实体") public class User { @ApiModelProperty("用户编号") private Long id; @ApiModelProperty("用户姓名") private String name; @ApiModelProperty("用户年龄") private Integer age; } 

    完成上述代码添加后,启动 Spring Boot 程序,访问:http://localhost:8080/swagger-ui.html,就能看到下面这样带中文说明的文档了(其中标出了各个注解与文档元素的对应关系以供参考):

    API 文档访问与调试

    在上图请求的页面中,我们看到 user 的 Value 是个输入框?是的,Swagger 除了查看接口功能外,还提供了调试测试功能,我们可以点击上图中右侧的 Model Schema (黄色区域:它指明了 User 的数据结构),此时 Value 中就有了 user 对象的模板,我们只需要稍适修改,点击下方“Try it out !”按钮,即可完成了一次请求调用!

    此时,你也可以通过几个 GET 请求来验证之前的 POST 请求是否正确。

    相比为这些接口编写文档的工作,我们增加的配置内容是非常少而且精简的,对于原有代码的侵入也在忍受范围之内。因此,在构建 RESTful API 的同时,加入 Swagger 来对 API 文档进行管理,是个不错的选择。

    代码示例

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

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

    2 条回复    2019-10-14 14:21:22 +08:00
    hantsy
        1
    hantsy  
       2019-10-14 12:31:15 +08:00
    从 API 命名上看,SpringFox 提供的 Swagger/OpenAPI 好像更友好一些。
    1. 支持 Security 吗,比如 OAuth 集成
    2. 支持扩展吗?比如自己定义的 Markdown,Asciidoc 片断,生成文档时合并到一起。
    hadixlin
        2
    hadixlin  
       2019-10-14 14:21:22 +08:00
    借楼,推荐一下自己的项目[SpringFox-Plus]( https://github.com/hadix-lin/springfox-plus),简化 spring 项目的 swagger 集成,支持接口分组,支持读取源代码的 javadoc 做为接口说明。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     937 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 18:58 PVG 02:58 LAX 11:58 JFK 14:58
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86