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


    前言

    通过之前的两篇文章,可以简单的搭建一个路由网关了。而我们知道,现在都奉行前后端分离开发,前后端开发的沟通成本就增加了,所以一般上我们都是通过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/

  • 相关阅读:
    查看crontab的日志记录定位定时任务问题
    Latex 表格内公式换行方法
    C语言中qsort函数用法
    7 种常用的排序算法-视觉直观感受
    Ubuntu下如何安装YouCompleteMe插件
    Linux下非root用户如何安装软件
    系统进化树-原理介绍及软件使用
    LaTeX 页眉页脚的设置
    TEXshade教程- 多重比对着色软件包
    easyUI自带的时间插件日期选择、月份选择、时间选择的使用
  • 原文地址:https://www.cnblogs.com/okong/p/springcloud-eleven.html
Copyright © 2020-2023  润新知