文档章节

白话SpringCloud | 第十一章:路由网关(Zuul):利用swagger2聚合API文档

oKong
 oKong
发布于 10/20 12:26
字数 1931
阅读 78
收藏 20

前言

通过之前的两篇文章,可以简单的搭建一个路由网关了。而我们知道,现在都奉行前后端分离开发,前后端开发的沟通成本就增加了,所以一般上我们都是通过swagger进行api文档生成的。现在由于使用了统一路由网关了,都希望各微服务的api文档统一的聚合在网关服务中,也方便前端用户查阅,不需要每个服务单独查看。当然了,也是可以做一个文档索引网页进行各微服务的api文档链接的。今天,我们就来讲下使用swagger实现自动化聚合微服务文档功能。

注:关于Swagger的介绍和使用,由于在之前的SpringBoot系列文章中有提及,这里就不在过多阐述了,不理解的可以点击:第十章:Swagger2的集成和使用进行查看,了解下基本用法。

Zuul聚合示例

为了实现自动聚合功能,简单来说就是通过Zuulapi获取所有的路由信息,根据其具体地址进行自动转配到SwaggerSwaggerResource下。

另外,为了项目的独立,本章节创建个maven多模块工程项目。整体结构如下:

项目结构

同时,会启动一个基于Eureka的注册服务,具体可以查看源码:spring-cloud-eureka-server

微服务端

为了演示,创建两个微服务spring-cloud-zuul-service-onespring-cloud-zuul-service-two

这里以构建spring-cloud-zuul-service-one为例,spring-cloud-zuul-service-two基本上是一样的,可以查看源码示例。

0.引入相关依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 客户端依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>		
		<!--swagger -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.0</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.0</version>
		</dependency> 

1.编写swagger配置类。

/**
 * swagger配置类
 * @author oKong
 *
 */
@EnableSwagger2
@Configuration
public class SwaggerConfig {

	//是否开启swagger,正式环境一般是需要关闭的,可根据springboot的多环境配置进行设置
	@Value(value = "${swagger.enabled}")
	Boolean swaggerEnabled;

	@Bean
	public Docket createRestApi() {
		return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
				// 是否开启
				.enable(swaggerEnabled).select()
				// 扫描的路径包
				.apis(RequestHandlerSelectors.basePackage("cn.lqdev.learning.springcloud.zuul.service"))
				// 指定路径处理PathSelectors.any()代表所有的路径
				.paths(PathSelectors.any()).build().pathMapping("/");
	}

	//设置api信息
	private ApiInfo apiInfo() {
		return new ApiInfoBuilder()
				.title("路由网关(Zuul):利用swagger2聚合API文档-service-one")
				.description("oKong | 趔趄的猿")
				// 作者信息
				.contact(new Contact("oKong", "https://blog.lqdev.cn/", "499452441@qq.com"))
				.version("1.0.0")
				.build();
	}
}

2.编写控制层,设置对外api服务信息,同时创建了请求响应的实体类。

DemoController.java

/**
 * demo示例
 * @author oKong
 *
 */
@RestController
@Api(tags="servicie-one服务")
@Slf4j
public class DemoController {

	@GetMapping("/hello")
	@ApiOperation(value="demo示例")
	public DemoResp hello(DemoReq demoReq) {
		log.info("DemoReq:{}", demoReq);
		
		return DemoResp.builder()
				.code(demoReq.getCode())
				.name(demoReq.getName())
				.remark(demoReq.getRemark())
				.build();
	}
}

DemoReq.java

/**
 * 请求实体
 * @author oKong
 *
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class DemoReq {

	@ApiModelProperty(name="code",value="编码",example="oKong")
	String code;
	
	@ApiModelProperty(name="name",value="名称",example="趔趄的猿")
	String name;
	
	@ApiModelProperty(name="remark",value="备注",example="blog:blog.lqdev.cn")
	String remark;
}

DemoResp.java

/**
 * 响应实体
 * @author Okong
 *
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class DemoResp {

	@ApiModelProperty(name="code",value="编码",example="oKong")
	String code;
	
	@ApiModelProperty(name="name",value="名称",example="趔趄的猿")
	String name;
	
	@ApiModelProperty(name="remark",value="备注",example="blog:blog.lqdev.cn")
	String remark;
}

3.编写启动类。

/**
 * api服务1 示例
 * @author oKong
 *
 */
@SpringBootApplication
@EnableDiscoveryClient
@Slf4j
public class ServiceOneApplication {

	public static void main(String[] args) throws Exception {
		SpringApplication.run(ServiceOneApplication.class, args);
		log.info("spring-cloud-zuul-service-one启动!");
	}
}

4.添加配置信息。

spring.application.name=api-service-one
server.port=789

# 注册中心地址 -此为单机模式
eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
eureka.instance.prefer-ip-address=true
# 实例名称  最后呈现地址:ip:2000
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
# swagger开关
swagger.enabled=true

5.启动应用,访问:http://127.0.0.1:789/swagger-ui.html 就可以单应用api文档配置成功了

service-one-swagger

路由网关端

创建项目:spring-cloud-zuul-gateway

关于zuul的使用,可以查看:第九章:路由网关(Zuul)的使用

0.引入相关依赖。

		<!-- zuul 依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
		<!-- 客户端依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!--swagger -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.0</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.0</version>
		</dependency>

1.添加相关配置信息。

spring.application.name=zuul-gateway
server.port=8899

# 注册中心地址 -此为单机模式
eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
# 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
eureka.instance.prefer-ip-address=true
# 实例名称  最后呈现地址:ip:15678
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

# swagger开启开关
swagger.enabled=true

2.编写swagger配置类(重点)

@EnableSwagger2
@Configuration
@Primary //多个bean时 此类优先使用
public class SwaggerConfig implements SwaggerResourcesProvider{

	//是否开启swagger,正式环境一般是需要关闭的,可根据springboot的多环境配置进行设置
	@Value(value = "${swagger.enabled}")
	Boolean swaggerEnabled;

	@Autowired
	RouteLocator routeLocator;
	
	@Bean
	public Docket createRestApi() {
		return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
				// 是否开启
				.enable(swaggerEnabled).select()
				// 扫描的路径包
				.apis(RequestHandlerSelectors.basePackage("cn.lqdev.learning.springcloud.zuul.swagger2"))
				// 指定路径处理PathSelectors.any()代表所有的路径
				.paths(PathSelectors.any()).build().pathMapping("/");
	}

	//设置api信息
	private ApiInfo apiInfo() {
		return new ApiInfoBuilder()
				.title("路由网关(Zuul):利用swagger2聚合API文档")
				.description("oKong | 趔趄的猿")
				// 作者信息
				.contact(new Contact("oKong", "https://blog.lqdev.cn/", "499452441@qq.com"))
				.version("1.0.0")
				.termsOfServiceUrl("https://github.com/xie19900123/")
				.build();
	}

	@Override
	public List<SwaggerResource> get() {
		//利用routeLocator动态引入微服务
		List<SwaggerResource> resources = new ArrayList<>();
		resources.add(swaggerResource("zuul-gateway","/v2/api-docs","1.0"));
		//循环 使用Lambda表达式简化代码
		routeLocator.getRoutes().forEach(route ->{
			//动态获取
			resources.add(swaggerResource(route.getId(),route.getFullPath().replace("**", "v2/api-docs"), "1.0"));
		});
		//也可以直接 继承 Consumer接口
//		routeLocator.getRoutes().forEach(new Consumer<Route>() {
//
//			@Override
//			public void accept(Route t) {
//				// TODO Auto-generated method stub
//				
//			}
//		});
		return resources;
	}
	
	private SwaggerResource swaggerResource(String name,String location, String version) {
		SwaggerResource swaggerResource = new SwaggerResource();
		swaggerResource.setName(name);
		swaggerResource.setLocation(location);
		swaggerResource.setSwaggerVersion(version);
		return swaggerResource;
	}
}

这里继承SwaggerResourcesProvider接口是实现聚合api的关键,另外通过RouteLocator类获取路由列表是实现自动聚合的关键。

当然,这里也是可以手动进行添加的。

3.编写zuul内部控制层。

/**
 * zuul 内部提供对外服务示例
 * @author oKong
 *
 */
@RestController
@RequestMapping("/demo")
@Api(tags="zuul内部rest api")
public class DemoController {

	@GetMapping("/hello")
	@ApiOperation(value="demo示例",notes="demo示例")
	@ApiImplicitParam(name="name",value="名称",example="oKong")
	public String hello(String name) {
		return "hi," + name + ",this is zuul api! ";
	}
}

4.编写启动类。

/**
 * zuul使用swagger2聚合微服务api示例
 * @author oKong
 *
 */
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
@Slf4j
public class ZuulSwaggerApplication {
	public static void main(String[] args) throws Exception {
		SpringApplication.run(ZuulSwaggerApplication.class, args);
		log.info("spring-cloud-zuul-gateway启动!");
	}
}

5.启动应用,访问:http://127.0.0.1:8899/swagger-ui.html 可以看见页面显示的是网关项目的swagger文档信息。

zuul-gate-swagger-ui

现在看看右上角的Select a spec下拉框,可以看见下拉框中包含了注册中心下的所有微服务了。

Select a spec

此时,我们切换下api-service-one,可以看见api-service-one的api列表了。

api-service-one

切换到api-service-two,也可以看见都要的api列表信息。

api-service-two

参考资料

  1. https://piotrminkowski.wordpress.com/2017/04/14/microservices-api-documentation-with-swagger2/

总结

本章节主要简单介绍了如何在Zuul路由网关服务利用Swagger2进行微服务api的聚合功能。这样查看各微服务的api文档就很方便,集中,不需要在切换不同文档地址了。

最后

目前互联网上大佬都有分享SpringCloud系列教程,内容可能会类似,望多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有错误之处,还望提出,谢谢。

老生常谈

  • 个人QQ:499452441
  • 微信公众号:lqdevOps

公众号

个人博客:http://blog.lqdev.cn

源码示例:https://github.com/xie19900123/spring-cloud-learning

以下教程可能你会感兴趣:

原文地址:https://blog.lqdev.cn/2018/10/19/SpringCloud/chapter-eleven/

© 著作权归作者所有

共有 人打赏支持
oKong
粉丝 555
博文 60
码字总数 144281
作品 0
福州
高级程序员
私信 提问
史上最简单的 SpringCloud 教程 | 终章

版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接 ,博主地址:http://blog.csdn.net/forezp。 https://blog.csdn.net/forezp/article/details/70148833 转载请标明出处...

方志朋
2017/04/12
0
0
史上最简单的 SpringCloud 教程

《史上最简单的 SpringCloud 教程》系列: 史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现(Eureka) 史上最简单的SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon) 史上最...

外星人et59
04/21
0
0
Spring Cloud Gateway 聚合swagger文档

关于pigX:全网最新的微服务脚手架,Spring Cloud Finchley、oAuth2的最佳实践 在微服务架构下,通常每个微服务都会使用Swagger来管理我们的接口文档,当微服务越来越多,接口查找管理无形中...

gggggwww
07/20
0
0
白话SpringCloud | 第零章:前言

说在前面 大清早醒来,觉得睡不着了。还是起来,写写博客。但最后发现关于的安全相关的还是比较多内容的,也比较专业,怕是一个多小时完不成的,也罢,那就来写写关于前言吧。 说明 《白话S...

oKong
09/04
0
0
SpringCloud之网关 Zuul(四)

一 Zuul简介 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。 Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix ...

07/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

RabbitMQ+PHP 教程三(Publish/Subscribe)用yii2测试通过

介绍 在前面的教程中,我们创建了一个工作队列。工作队列背后的假设是每个任务都交付给一个工作人员处理。在这一部分中,我们将做一些完全不同的事情——我们将向多个消费者发送消息。此模式...

hansonwong
21分钟前
2
0
关于JAVA你必须知道的那些事(四):单例模式和多态

好吧,今天一定要把面向对象的最后一个特性:多态,给说完。不过我们先来聊一聊设计模式,因为它很重要。 设计模式 官方的解释是,设计模式是:一套被反复使用,多数人知晓的,经过分类编目,...

拾光TM
21分钟前
1
0
ES6 系列之 Babel 是如何编译 Class 的(下)

摘要: ## 前言 在上一篇 [《 ES6 系列 Babel 是如何编译 Class 的(上)》](https://github.com/mqyqingfeng/Blog/issues/105),我们知道了 Babel 是如何编译 Class 的,这篇我们学习 Babel ...

阿里云官方博客
22分钟前
1
0
附实例!实现iframe父窗体与子窗体的通信

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由前端林子发表于云+社区专栏 本文主要会介绍如何基于MessengerJS,实现iframe父窗体与子窗体间的通信,传递数据信息。同时本...

腾讯云加社区
28分钟前
1
0
JSP页面传List集合到Action中

1:JSP页面(前端用的是H-UI框架) <div class="codeView docs-example"> <table class="table table-border table-bordered table-striped"> <thead> ......

uug
32分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部