前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud 之服务网关 Gateway(二) 集成 Swagger 组件

Spring Cloud 之服务网关 Gateway(二) 集成 Swagger 组件

作者头像
芥末鱿鱼
发布2020-09-22 10:32:32
1.9K0
发布2020-09-22 10:32:32
举报
文章被收录于专栏:玩转 Spring Cloud

Spring Cloud 之服务网关 Gateway(二) 集成 Swagger 组件

概述

Swagger 是一个可视化 API 测试工具, 能够有效的构建强大的 Restful API 文档, 省去接口文档管理工作. 如果修改了代码, API 文档也会实时更新. 并且可以部分替代 Postman 用来调试接口

Spring Boot 整合了 swagger 组件, 使用也比较简单. 微服务随着项目的增加, 访问每一个应用的 swagger 显然是不合适的. 我们希望网关可以将所有的应用的 swagger 页面聚合起来. 这样前端只要访问网关的 swagger 的就可以了

Spring Cloud Gateway 整合 Swagger 会有一个麻烦, Gateway 底层是 WebFlux, 而 WebFlux 和 Swagger 不兼容. 所以不能通过一般的 Spring Boot 项目的方式简单的整合 Swagger, 否则启动的时候会报错. 常用的做法是自定义几个配置类来实现

编写简单案例

聚合模块说明

  • 版本说明 Spring Boot : 2.0.9.RELEASE Spring Cloud: Finchley.RELEASE
  • 项目整体结构采用 maven 多 Module 结构 模块端口说明Demo父项目Eureka15002注册中心Gateway15000网关Comment15003应用服务
  • 项目树 一个注册中心 一个网关 一个应用服务 |_ demo |_ eureka |_ gateway |_ comment |_ pom.xml

编写 Eureka 服务

参考: Spring Cloud 之 Eureka 服务注册与发现

配置信息

编写应用程序服务 Comment-server

  • 编写 pom 文件 <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> </dependencies>
  • 编写工程的配置文件, eureka: client: service-url: defaultZone: http://localhost:15002/eureka/ instance: lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 15 perfer-in-address: true server: port: 15003 spring: application: name: comment-server profiles: active: dev
  • 编写配置类 @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi(){ return new Docket(DocumentationType.SWAGGER_2)// .apiInfo(apiInfo())// .select()// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))// .paths(PathSelectors.any())// .build(); } private ApiInfo apiInfo(){ return new ApiInfoBuilder()// .title("Swagger API")// .description("test")// .termsOfServiceUrl("")// .contact(new Contact("Spring Cloud China","http://springcloud.cn",""))// .version("2.0")// .build(); } }
  • 编写控制器 @RestController @RequestMapping("/comments") @Slf4j @Api("comments") public class CommentController { @Autowired private CommentService commentService; @ApiOperation(value = "获取评论详情", notes = "根据评论 id 获取详情") @ApiParam(value = "评论id") @GetMapping("/detail/{id}") public String getCommentDetails(@PathVariable("id") String id) { log.debug("Get comment by id [{}]", id); return id; } }
  • 验证效果 服务启动后, 通过访问 http://localhost:15003/swagger-ui.html 访问 API 文档界面

编写 Gateway 网关服务

  • 编写 pom 文件 <dependencies> <!-- 健康监控 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- Spring Cloud Gateway 依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</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-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> </dependencies>
  • application.yml 文件配置 spring: application: name: gateway cloud: gateway: discovery: locator: enabled: true # 开启基于服务发现的路由规则 lower-case-service-id: true # 开启小写的 serviceId 进行基于服务路由的转发 routes: - id: comment_server_route uri: lb://comment-server # 路由集群内其他服务,url需要用[lb://]+[serviceId] predicates: - Path=/comment/** filters: - SwaggerHeaderFilter - StripPrefix=1 loadbalancer: retry: enabled: true # 内部已默认开启负载均衡 eureka: client: service-url: defaultZone: http://localhost:15002/eureka/ # 指定注册中心地址, 以便使用服务发现功能 instance: lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 15 perfer-in-address: true server: port: 15000 management: endpoints: health: enabled: true gateway: enabled: true web: exposure: include: "*" # 暴露所有端点, 默认是 info, health logging: level: org.springframework.cloud.gateway: debug
  • 配置 GatewaySwaggerProvider, 获取 Api-doc, 即 GatewaySwaggerProvider @Component @Primary public class GatewaySwaggerProvider implements SwaggerResourcesProvider { public static final String API_URI = "/v2/api-docs"; private final RouteLocator routeLocator; private final GatewayProperties gatewayProperties; public GatewaySwaggerProvider(RouteLocator routeLocator, GatewayProperties gatewayProperties) { this.routeLocator = routeLocator; this.gatewayProperties = gatewayProperties; } @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); List<String> routes = new ArrayList<>(); // 取出 Spring Cloud Gateway 中的 route routeLocator.getRoutes()// .subscribe(route -> routes.add(route.getId())); // 结合 application.yml 中的路由配置, 只获取有效的 route 节点 gatewayProperties.getRoutes().stream()// .filter(routeDefinition -> routes.contains(routeDefinition.getId()))// .forEach(routeDefinition -> routeDefinition.getPredicates().stream()// .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName().toLowerCase()))// .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()// .get(NameUtils.GENERATED_NAME_PREFIX + "0")// .replace("/**", API_URI))))); return resources; } private SwaggerResource swaggerResource(String name, String location) { SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(name); swaggerResource.setLocation(location); swaggerResource.setSwaggerVersion("2.0"); return swaggerResource; } }
  • 编写 swagger-resource 端点 @RestController @RequestMapping("/swagger-resources") public class SwaggerHandler { @Autowired(required = false) private SecurityConfiguration securityConfiguration; @Autowired(required = false) private UiConfiguration uiConfiguration; private final SwaggerResourcesProvider swaggerResources; @Autowired public SwaggerHandler(SwaggerResourcesProvider swaggerResources) { this.swaggerResources = swaggerResources; } @GetMapping("/configuration/security") public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("/configuration/ui") public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("") public Mono<ResponseEntity> swaggerResources() { return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); } }
  • 配置过滤器 (**Finchley.SR2 版本可跳过这一步, 配置文件里的 - SwaggerHeaderFilter 也不用配置 **) @Component public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory { private static final String HEADER_NAME = "X-Forwarded-Prefix"; @Override public GatewayFilter apply(Object config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); String path = request.getURI().getPath(); if(!StringUtils.endsWithIgnoreCase(path, GatewaySwaggerProvider.API_URI)){ return chain.filter(exchange); } String basePath = path.substring(0,path.lastIndexOf(GatewaySwaggerProvider.API_URI)); ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME,basePath).build(); ServerWebExchange newExchange = exchange.mutate().request(newRequest).build(); return chain.filter(newExchange); }; } }
  • 启动类 @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }

发送请求测试效果

注册中心(eureka), 网关服务(gateway) 和应用服务(comment-server)依次启动后, 访问 http://localhost:15000/swagger-ui.html 可以看到 swagger 页面

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 编写简单案例
    • 聚合模块说明
      • 编写 Eureka 服务
        • 编写应用程序服务 Comment-server
          • 编写 Gateway 网关服务
            • 发送请求测试效果
            相关产品与服务
            微服务引擎 TSE
            微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档