![微服务分布式架构基础与实战:基于Spring Boot + Spring Cloud](https://wfqqreader-1252317822.image.myqcloud.com/cover/390/31186390/b_31186390.jpg)
3.2 【实例】微服务集成Swagger
3.2.1 实例背景
本实例将使用微服务集成Swagger,并在Consul中进行注册,为其他服务的调用做准备。本实例还将创建cloud-user-8083工程和cloud-common-jar工程。cloud-common只作为依赖Jar包存在,并为其他工程提供相应的实体类,不整合Boot或Cloud。限于篇幅本书不再介绍cloud-common工程。若在生产项目中,则应新建cloud-parent工程,规定依赖的版本号,将众多微服务的Maven依赖版本保持一致。
本书在工程命名的时候通常将项目的版本号写在工程名和启动类名里,只是为了测试时在Eclipse的Console控制台中显示更加直观。通常将工程名书写为“项目名-微服务名-端口号”,启动类名书写为“ApplicationMain”或“微服务名+AppMain”,配置文件中的spring.application.name分布式微服务名书写为“项目名-微服务名”等。注意,不可使用下画线“_”,因为下画线在Cloud通信中可能会报错。
3.2.2 编写Swagger依赖
Swagger需要引入springfox-swagger2和springfox-swagger-ui的依赖。pom.xml文件所需增加的部分代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_75_1.jpg?sign=1739562884-o8y0is0qIhhPQ9BQ1bPs2gHWiOGLJR9d-0-9be96785940af03df7cf922f6f57bec7)
注意,Server端不需要使用Feign进行依赖,声明式服务调用只需要在Client端进行依赖即可。
3.2.3 编写Swagger配置
创建Swagger2.java文件,Swagger2.java文件用于Swagger的基本配置,代码如下。另外,Spring的YAML资源配置文件与2.3节中的资源配置文件基本相同,不再赘述。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_76_2.jpg?sign=1739562884-9SF5cNbEpplH2tX4xa0p91EKUqbG9fnb-0-1110a78d8fde2c64a09fdc11da325ccc)
@Configuration注解将Swagger2的相关配置注册到Spring容器中。
@EnableSwagger2注解开启Swagger2的相关注解和功能,开启的相关注解包括Swagger2的@Api和@ApiOperation等。
在Swagger2的配置中,相当于将Docket注册到Spring容器中,Docket是Swagger2的构造器,Swagger是基于Spring MVC构建的,Docket提供合理的默认值和方便的配置方法。Docket对象可配置的参数及释义如表3-1所示。
表3-1 Docket对象可配置的参数及释义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_77_1.jpg?sign=1739562884-7QMUpybZKz6pLGrAxdGqO2CcaLi2nyJw-0-05469fef339adfc1d9c33dbc668df78f)
apiInfo可配置的参数及释义如表3-2所示。
表3-2 apiInfo可配置的参数及释义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_77_2.jpg?sign=1739562884-TtpjMT11En1HEIodBzMTVnBR2PPUklte-0-1aaa0476ba2e045f278db861a3fadf76)
3.2.4 编写接口与接口处的Swagger配置
为方便观察运行效果,在UserController.java文件中编写部分用于测试的接口。每个接口都只返回一个固定参数并打印相关日志,代码如下。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_77_3.jpg?sign=1739562884-prIyKH9zoJRL7MY9Hf5JoIm74VN4BBpG-0-ff61121d3c973757f3cc84b069777a53)
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_78_1.jpg?sign=1739562884-OaOLlK1VR3wyc0255o3AYLc0bydryykA-0-c56d8c4d7d1bc8c58e512b89e2d86d89)
UserController类定义了3个接口,为了展示运行效果,每个接口都使用Swagger的描述性注解修饰,如下。
@ApiImplicitParams注解:引入其他自定义的@ApiImplicitParam资源。
@ApiImplicitParam注解:强行自定义部分入参资源,也可使Swagger自动生成,如果自定义可多写描述信息。
@ApiOperation注解:描述针对特定路径的操作或HTTP方法。HTTP方法与路径的组合将创建一个唯一的操作。在注解不被定义的情况下Swagger也会运行,但为了给每个接口描述信息,会编写该注解。@ApiOperation注解配置的参数及释义如表3-3所示。
表3-3 @ApiOperation注解配置的参数及释义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_78_2.jpg?sign=1739562884-5GKfCNIzy8rpvcyNccY45Zrq8458XYK2-0-bb94d637a404c318b8c116005ff56ab6)
3.2.5 当前项目结构
启动类与2.3节中的启动类相同。
图3-1的cloud-user-8083工程依赖于图3-2的cloud-common-jar工程,本实例将运行cloud-user-8083工程,运行后观察Swagger生成的在线文档。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_79_2.jpg?sign=1739562884-imJAYRzkCCdFxGgou1qnJH6Sk16KTmTo-0-e2bd202e146267bedd78147a021503e6)
图3-1
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_79_3.jpg?sign=1739562884-5MuRSXQHup9zMVl4POzIZWUKjvqYBD5Y-0-a63c07dccdcb3b100ac222832165f75b)
图3-2
3.2.6 运行效果
1.运行查看Swagger UI页面
运行后输入Swagger默认的浏览地址:http://localhost:8083/swagger-ui.html,可查看Swagger生成的页面,如图3-3所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_80_1.jpg?sign=1739562884-iOdVyJxnyycHrXpdcqp4lWh7qNpd1dr3-0-a2b92e7b3bad3f8ff57fbdfc88164595)
图3-3
在Swagger UI页面中可观察目前所有Swagger扫描的接口,而且Swagger2.java类中Swagger配置的相关文档注释都作为标题等元素显示在Swagger UI中。
2.观察UserController中被Swagger扫描到的接口
由于getUser1接口的@ApiOperation注解中设置了tags参数“UserController”,所以Swagger默认将该接口设置了自己的分组。从页面上可以看出,如果不设置tags,Swagger会以Controller.class进行默认分组,如图3-4所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_80_2.jpg?sign=1739562884-6UhGsjBymtmRFUtAvHUFyzj6sUztqZG2-0-e5815918caf255bd84ddadae9c3dd06c)
图3-4
3.观察没有被@ApiOperation注解修饰的接口
虽然没有在ApplicationMain8083.class启动类中编写@ApiOperation,但由于Swagger默认扫描该工程下的全部接口,所以Consul健康检查接口也被写入Swagger UI中,如图3-5所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_80_3.jpg?sign=1739562884-Ki1BLm95ufR4kb02TjnjqdaoVd109c9I-0-359abf00efab8498d1d139f2e211fec8)
图3-5
如果@RequestMapping注解不标识使用哪种RequestMethod,Swagger中的每个RequestMethod类型都会被写入,但不建议使用这种方式,因为接口太多不容易查询。
4.观察getUser1接口
单击getUser1选项显示该接口的详细列表,包括之前输入的以下相关信息,如图3-6所示。
Implementation Notes:操作详情。
Response Class:响应的HTTP状态码和返回参数类型,返回的参数是User对象。
Parameters中的Value:入参json。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_81_1.jpg?sign=1739562884-Zy2AW2pG9fwdEDZkUwdez8aA13Rcen29-0-2a77048dc8050c8a3ebdb27318edd253)
图3-6
单击Model Schema选项,会将需要使用的数据转换为json格式,并复制到Value文本框中,如图3-7所示。也可以自行编写所需要输入的参数。Model Schema也可以自定义格式,以减少一些不必要的内置参数。@ApiOperation注解的response参数输入类型为Class<?>,Swagger会将要求的入参Class<?>转换成自身所使用的Model Schema,并辅助其作为入参使用。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_82_1.jpg?sign=1739562884-iBwp6H3BeLxaEjM0HNWFmnEX8DcKMOiR-0-29059450f9bb88a7b6283277fbcf14a1)
图3-7
5.调用getUser1接口
更改Parameter入参中的Value后,单击Try it out!按钮即可调用getUser1接口,如图3-8所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_82_2.jpg?sign=1739562884-yjCGe1dn7C6ttqgYR5jRWLPQLhFyi6Je-0-5f06a8e78e81731d8af48449568b79f1)
图3-8
返回结果如图3-9所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_83_1.jpg?sign=1739562884-kohJgG5jdm4x0UUgQcWxD8mDZf7wcUq7-0-e2d720ee7001d6e1c3deec964dd0d0e9)
图3-9
Curl文本框中的内容代表Swagger生成了利用Linux Curl工具调用getUser1接口的命令和调用该接口需要的入参,利用Linux控制台直接复制内容,调用结果如图3-10所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_83_2.jpg?sign=1739562884-zNDhOoEaBqBoAxqe895jUCLREiwH5M3e-0-08fad114fcbb911b483b6c7deb756be9)
图3-10
通过返回的响应体name,调用已经到后台了,后台输出如图3-11所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_83_3.jpg?sign=1739562884-eZFVw6PVjflSAzyGJCNjK3v9iGg7XsWn-0-5eead6b6158476d9a13d525f2a18e82c)
图3-11
注意,Swagger是真实进行调用,如果调用的接口操作数据库,数据库也会直接进行操作。
3.2.7 实例易错点
1.注解中的返回类型
@ApiOperation注解的produces参数写成application/json1,可视化页面如图3-12所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_83_4.jpg?sign=1739562884-F0jbr7pmSu9tUfl84f9tvRTck9XvOFW8-0-53f59acc6666d8e5c66f00f54c24fff2)
图3-12
HTTP无法识别此类型,即使传入参数也会出现相应错误,如图3-13所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_84_1.jpg?sign=1739562884-A2cO57qap9sIotUvCnEa24kqZpYMhTXZ-0-c2da9119f730f95aebd74ac5f006e38f)
图3-13
HTTP无法受理这些类型,除非自定义其编码格式。HTTP的传输编码格式如表3-4所示。
表3-4 HTTP的传输编码格式
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_84_2.jpg?sign=1739562884-TDlqgbfvo2FH5RYNnv5tAHQt2cdZQYoq-0-19d35d8d1c63c9154513093e351f724c)
2.返回值不可加toString()函数
因为使用@RestController注解,其内部含有@ResponseBody注解,所以可以自动将返回值转化成json类型。若返回时再加上toString(),则Swagger UI无法正常调用。由于调用增加了toString()的getUser3接口,所报错误如图3-14所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_85_1.jpg?sign=1739562884-TeOKYpSi6t3wLtfzs3Jea5fKXHV999fS-0-4cb5b7020b7dbf63ad5d3ab42b1d8032)
图3-14
此处也会产生一个冲突问题,如果用Feign调用其他接口,其他接口若返回toString()后的参数,Feign相关内容都不会报错,但Swagger会报错。因此为了程序统一,都不加toString()函数,以避免出现此类错误。
注意,加上toString()函数,后台不会有任何异常,如图3-15所示。
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_85_2.jpg?sign=1739562884-fNoCTJcJvoiypzP995KDn6Fr4IFVjSA9-0-73f3d3b4fee0a6264efd49f10685387b)
图3-15
3.Swagger的常见注解
表3-5所示为Swagger的常见注解及释义。
表3-5 Swagger的常见注解及释义
![](https://epubservercos.yuewen.com/C493B8/16896238005622406/epubprivate/OEBPS/Images/38413_85_3.jpg?sign=1739562884-8T8r7hNOktrDWi2arFg143X3PxYqGg9G-0-47747709c47415db901374d120350f2c)