AdaKing88
2023-08-23 ae35159387a55199e8ab150ebb97d89d68a235bd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package org.jeecg.handler.swagger;
 
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.*;
 
/**
 * 聚合各个服务的swagger接口
 * @author zyf
 * @date: 2022/4/21 10:55
 */
@Component
@Slf4j
@Primary
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {
    /**
     * swagger2默认的url后缀
     */
    private static final String SWAGGER2URL = "/v2/api-docs";
 
    /**
     * 网关路由
     */
    private final RouteLocator routeLocator;
 
    /**
     * nacos服务地址
     */
    @Value("${spring.cloud.nacos.discovery.server-addr}")
    private String serverAddr;
    /**
     * nacos namespace
     */
    @Value("${spring.cloud.nacos.discovery.namespace:#{null}}")
    private String namespace;
    
    /**
     * Swagger中需要排除的服务
     */
    private String[] excludeServiceIds=new String[]{"jeecg-cloud-monitor"};
 
 
    /**
     * 网关应用名称
     */
    @Value("${spring.application.name}")
    private String self;
 
    @Autowired
    public MySwaggerResourceProvider(RouteLocator routeLocator) {
        this.routeLocator = routeLocator;
    }
 
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routeHosts = new ArrayList<>();
        // 获取所有可用的host:serviceId
        routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
                .filter(route -> !self.equals(route.getUri().getHost()))
                .subscribe(route ->{
                    //update-begin---author:zyf ---date:20220413 for:过滤掉无效路由,避免接口文档报错无法打开
                    boolean hasRoute=checkRoute(route.getId());
                    if(hasRoute){
                        routeHosts.add(route.getUri().getHost());
                    }
                    //update-end---author:zyf ---date:20220413 for:过滤掉无效路由,避免接口文档报错无法打开
                });
 
        // 记录已经添加过的server,存在同一个应用注册了多个服务在nacos上
        Set<String> dealed = new HashSet<>();
        routeHosts.forEach(instance -> {
            // 拼接url
            String url = "/" + instance.toLowerCase() + SWAGGER2URL;
            if (!dealed.contains(url)) {
                dealed.add(url);
                log.info(" Gateway add SwaggerResource: {}",url);
                SwaggerResource swaggerResource = new SwaggerResource();
                swaggerResource.setUrl(url);
                swaggerResource.setSwaggerVersion("2.0");
                swaggerResource.setName(instance);
                //Swagger排除不展示的服务
                if(!ArrayUtil.contains(excludeServiceIds,instance)){
                    resources.add(swaggerResource);
                }
            }
        });
        return resources;
    }
 
    /**
     * 检测nacos中是否有健康实例
     * @param routeId
     * @return
     */
    private Boolean checkRoute(String routeId) {
        Boolean hasRoute = false;
        try {
            //修复使用带命名空间启动网关swagger看不到接口文档的问题
            Properties properties=new Properties();
            properties.setProperty("serverAddr",serverAddr);
            if(namespace!=null && !"".equals(namespace)){
                properties.setProperty("namespace",namespace);
            }
            NamingService naming = NamingFactory.createNamingService(properties);
            
            List<Instance> list = naming.selectInstances(routeId, true);
            if (ObjectUtil.isNotEmpty(list)) {
                hasRoute = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hasRoute;
    }
}