博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用SpringCloud Alibaba搭建属于自己的微服务(二十五)~基础搭建~gateway整合swagger接口文档
阅读量:4205 次
发布时间:2019-05-26

本文共 9620 字,大约阅读时间需要 32 分钟。

一.概述

在springboot的单体工程中,整合swagger接口文档我们已经做好.现在加入了gateway网关了,所有的请求要是先经过gateway网关,gateway网关再路由转发到对应的微服务上.那么gateway整合所有微服务的swagger接口文档势在必行.

二.整合的思路

1.分析

swagger接口文档的本质是,swagger的包中有html界面,也有实现了的接口,界面上访问这些接口获取到有所有接口的信息,并且模拟http请求.打开swagger的html界面,我们就可以看到这些接口.

在这里插入图片描述

2.思路

思路其实还是简单的,页面上的数据来源于4个接口,我们在gateway中对这四个接口该重写的重写,响应的数据中该替换的替换就行了.

三.gateway整合swagger

1.gateway.pom中加入swagger的依赖.

io.springfox
springfox-swagger2
io.swagger
swagger-models
io.springfox
springfox-swagger-ui
io.swagger
swagger-models

2.重写swagger页面上的几个接口.

(1).控制层
package com.ccm.gateway.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Mono;import springfox.documentation.swagger.web.*;import java.util.Optional;/** * @Author: ccm * @CreatedDateTime: 2020/8/5 10:02 * @Description: 重写swagger页面上的几个接口控制层 */@RestController@RequestMappingpublic class SwaggerController {
@Autowired(required = false) private SecurityConfiguration securityConfiguration; @Autowired(required = false) private UiConfiguration uiConfiguration; private final SwaggerResourcesProvider swaggerResources; @Autowired public SwaggerController(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources; } @GetMapping("/swagger-resources/configuration/security") public Mono
> securityConfiguration() {
return Mono.just(new ResponseEntity<>( Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("/swagger-resources/configuration/ui") public Mono
> uiConfiguration() {
return Mono.just(new ResponseEntity<>( Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("/swagger-resources") public Mono
swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); } @GetMapping(value = "/") public Mono
swaggerResourcesRoot() { return Mono.just((new ResponseEntity<>(HttpStatus.OK))); } @GetMapping("/csrf") public Mono
swaggerResourcesCROF() { return Mono.just((new ResponseEntity<>(HttpStatus.OK))); }}
(2).业务层
package com.ccm.gateway.service.impl;import lombok.AllArgsConstructor;import org.springframework.cloud.gateway.config.GatewayProperties;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.cloud.gateway.support.NameUtils;import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;import springfox.documentation.swagger.web.SwaggerResource;import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList;import java.util.List;/** * @Author: ccm * @CreatedDateTime: 2020/8/5 10:51 * @Description: gateway整合swagger,中获取swaggerresource的实现 */@AllArgsConstructor@Primary    //容器中两个相同的Bean,优先注入,保证注入的不是默认的实现@Componentpublic class SwaggerResourcesImpl implements SwaggerResourcesProvider {
public static final String API_URI = "/v2/api-docs"; private final RouteLocator routeLocator; private final GatewayProperties gatewayProperties; @Override public List
get() {
List
resources = new ArrayList<>(); List
routes = new ArrayList<>(); //取出gateway的route routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); //结合配置的route-路径(Path),和route过滤,只获取有效的route节点 gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())) .forEach(routeDefinition -> routeDefinition.getPredicates().stream() .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName())) .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; }}

3.修改swagger中发起http请求的basePath(根路径).

(1).目的:修改这个值.

在这里插入图片描述

上一篇文章中,已经介绍了gateway过滤器的三种实现方式.GlobalFilter、GatewayFilter和AbstractGatewayFilterFactory,这里修改basePath是作用在所有路由,所以我选择使用GlobalFilter更加简洁.

(2).加入替换swagger的basePath全局过滤器.
package com.ccm.gateway.filter;import com.ccm.gateway.service.impl.SwaggerResourcesImpl;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.reactivestreams.Publisher;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.io.buffer.DataBuffer;import org.springframework.core.io.buffer.DataBufferFactory;import org.springframework.core.io.buffer.DataBufferUtils;import org.springframework.http.server.reactive.ServerHttpResponse;import org.springframework.http.server.reactive.ServerHttpResponseDecorator;import org.springframework.stereotype.Component;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Flux;import reactor.core.publisher.Mono;import java.nio.charset.Charset;import java.util.Arrays;/** * @Author: ccm * @CreatedDateTime: 2020/08/05 10:15 * @Description: gateway整合swagger2替换basepath路径 */@Slf4j@Componentpublic class SwaggerBasePathFilter implements GlobalFilter {
@Override public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//判断是否需要过滤 String path = exchange.getRequest().getURI().getPath(); if(StringUtils.endsWithIgnoreCase(path, SwaggerResourcesImpl.API_URI)) {
//为swagger2视图请求接口的地址 ServerHttpResponse originalResponse = exchange.getResponse(); DataBufferFactory bufferFactory = originalResponse.bufferFactory(); ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override public Mono
writeWith(Publisher
body) {
if (body instanceof Flux) {
Flux
fluxBody = (Flux
) body; return super.writeWith(fluxBody.map(dataBuffer -> {
// probably should reuse buffers byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); //释放掉内存 DataBufferUtils.release(dataBuffer); //s就是response的值,想修改、查看就随意而为了 String serverName = Arrays.stream(path.split("/")).filter(StringUtils::isNotBlank).findFirst().get(); content = new String(content, Charset.forName("UTF-8")).replaceFirst("\"basePath\" ?: ?\"[^\"]*\"", "\"basePath\":\"/" + serverName + "\"").getBytes(); byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes(); return bufferFactory.wrap(uppedContent); })); } // if body is not a flux. never got there. return super.writeWith(body); } }; // replace response with decorator return chain.filter(exchange.mutate().response(decoratedResponse).build()); } return chain.filter(exchange); }}

四.测试(这里为了增加演示效果,我们启动两个微服务)

(1).gateway中配置server-user和server-basic两个微服务的路由.

server:  port: 200  #服务端口spring:  application:    name: gateway #服务名称  cloud:    nacos:      discovery:        server-addr: 47.96.131.185:8848 #nacos服务的注册和发现地址    #gateway组件相关配置    gateway:      discovery:        locator:          enabled: true #开启基于服务的注册和发现的路由转发,默认轮询模式      routes: #路由配置        - id: server-user #路由名称,不配默认为UUID          uri: lb://server-user #满足断言的路由到此服务          predicates: #为一个数组,每个规则为并且的关系            - Path=/api-user/** #断言表达式,如果args不写key的,会自动生成一个id,如下会生成一个xxx0的key,值为/foo/*          filters: #请求路由转发前执行的filter,为数组            - StripPrefix=1  #缩写,和name=StripPrefix,args,参数=1是一个意思,该过滤器为路由转发过滤去        - id: server-basic #路由名称,不配默认为UUID          uri: lb://server-basic #满足断言的路由到此服务          predicates: #为一个数组,每个规则为并且的关系            - Path=/api-basic/** #断言表达式,如果args不写key的,会自动生成一个id,如下会生成一个xxx0的key,值为/foo/*          filters: #请求路由转发前执行的filter,为数组            - StripPrefix=1  #缩写,和name=StripPrefix,args,参数=1是一个意思,该过滤器为路由转发过滤去

(2).启动server-user和server-basic服务.

在这里插入图片描述在这里插入图片描述

(3).启动gateway.

在这里插入图片描述

(4).打开gateway的swagger界面.

在这里插入图片描述

可以看到gateway整合swagger成功了,并且右上角的下拉框可以选择我们的微服务,效果很棒.

(5).通过swagger随便访问一个server-user服务的接口.

在这里插入图片描述

访问也成功.

您的点赞、收藏、转发和关注是我持续创作的动力!

源码地址:

转载地址:http://lktli.baihongyu.com/

你可能感兴趣的文章