1. 定义swagger数据源

首先,我们需要从spring cloud gateway中配置的路由信息中获取路径

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
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;
import java.util.stream.Collectors;

@Component
@Primary
public class SwaggerResources implements SwaggerResourcesProvider {

    @Autowired
    private RouteLocator routeLocator;
    @Value("${spring.application.name}")
    private String gatewayServiceName;

    @Override
    public List<SwaggerResource> get() {
        List<Route> routeList=new ArrayList<>();
        routeLocator.getRoutes()
                 //排除springcloudgateway本身
                .filter(route -> !route.getUri().getHost().equals(gatewayServiceName))
                .subscribe(route->routeList.add(route));
        return routeList.stream().distinct().map(route -> {
            //这里我们是在路由配置中的metaData中添加了服务名称,我们把他作为swagger的groupName,也就是swagger页面右上角下拉框
            String groupName=(String) route.getMetadata().get("name");
            String url = "/"+route.getId()+"/v3/api-docs?group="+groupName;
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setUrl(url);
            swaggerResource.setName(groupName);
            swaggerResource.setSwaggerVersion("3.0.3");
            return swaggerResource;
        }).collect(Collectors.toList());
    }
}

微信截图_20210812105842.png
这里,swagger是通过inferred url来确定访问接口的跟路径,这个inffered url是通过/swagger-resources这个接口来确定的,返回结果如图:
微信截图_20210812110204.png
但是,我们现在的IP和端口号是网关的,它返回的路径服务本身的根路径,只能通过服务自己去访问,网关无法访问。所以这里我们需要对返回的内容做处理,也就是加上路由到服务的路径,这样我们就可以通过网关路由到每个服务的/v3/api-docs这个接口。

2. 为swagger创建一个Filter

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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.HttpStatus;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author pf
 * @date 2021/6/3 16:17
 */
@Component
public class SwaggerBaseInferredUrlFilter implements GlobalFilter, Ordered {

    private ObjectMapper objectMapper=new ObjectMapper();

    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //仅限swagger过滤:/v3/api-docs
        if(exchange.getRequest().getPath().toString().indexOf("/v3/api-docs")==-1){
            return chain.filter(exchange);
        }
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux&&originalResponse.getStatusCode().equals(HttpStatus.OK)) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                        DataBuffer join = bufferFactory.join(dataBuffer);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        DataBufferUtils.release(join);
                        String responseData = new String(content, Charset.forName("UTF-8"));
                        //截断问题处理
                        responseData = responseData.replaceAll(":null", ":\"\"");
                        try {
                            Map map=objectMapper.readValue(responseData, Map.class);
                            List<LinkedHashMap<String,String>> servers= (List<LinkedHashMap<String,String>>) map.get("servers");
                            servers.forEach(server->{
                                String inferredUrl=server.get("url");
                                //这里需要注意,我的服务路由用的是一截路径,所以就这样处理了
                                inferredUrl+="/"+exchange.getRequest().getPath().toString().split("/")[1];
                                server.put("url",inferredUrl);
                            });
                            map.put("servers",servers);
                            responseData=objectMapper.writeValueAsString(map);
                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                        }
                        byte[] uppedContent = responseData.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());
    }
}

效果应该是这样:
微信截图_20210812111315.png