You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2022/07/04 04:32:18 UTC

[incubator-shenyu] branch master updated: [ISSUE 3623][admin] API document enhancement and Optimization: supports the "spring cloud" plug-in and fix bug. (#3649)

This is an automated email from the ASF dual-hosted git repository.

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new afa69b88c [ISSUE 3623][admin] API document enhancement and Optimization: supports the "spring cloud" plug-in and fix bug. (#3649)
afa69b88c is described below

commit afa69b88cc12c1e5742424d10e75483fdef56a2a
Author: lianjunwei <13...@users.noreply.github.com>
AuthorDate: Mon Jul 4 12:32:12 2022 +0800

    [ISSUE 3623][admin] API document enhancement and Optimization: supports the "spring cloud" plug-in and fix bug. (#3649)
    
    * apidoc sql
    
    * refact
    
    * commit
    
    * [Task] Shenyu-admin: Fix API document failed to build because of NPE.
    
    * [Task] Shenyu-admin: Fix API document failed to build because of NPE.
    
    * solve conficts,modify LICENSE.
    
    * [ISSUE 3623][admin] API document enhancement and Optimization: pulling the swagger file supports the "spring cloud" plug-in.
    
    * [ISSUE 3623][admin] API document enhancement and Optimization: supports the "spring cloud" plug-in and fix bug.
    
    * delete useless code.
    
    * Undo changes to static files.
    
    * Undo changes to static files.
    
    * solve Server-side request forgery.
    
    * solve Server-side request forgery.
    
    * delete useless code.
    
    * solve Server-side request forgery.
    
    * pull api document needs startTime.
    
    Co-authored-by: lianjunwei <li...@didiglobal.com>
---
 .../shenyu/admin/controller/ApiDocController.java  |  14 +-
 .../shenyu/admin/controller/SandboxController.java | 146 +++++++++------------
 .../shenyu/admin/model/dto/ProxyGatewayDTO.java    | 139 ++++++++++++++++++++
 .../shenyu/admin/model/query/SelectorQuery.java    |  30 +++++
 .../shenyu/admin/service/AppAuthService.java       |   9 ++
 .../admin/service/impl/AppAuthServiceImpl.java     |   9 +-
 .../manager/impl/LoadServiceDocEntryImpl.java      | 131 ++++++++++--------
 .../service/manager/impl/SwaggerDocParser.java     |   3 +-
 .../shenyu/admin/utils/CommonUpstreamUtils.java    |   2 +-
 .../src/main/resources/mappers/selector-sqlmap.xml |   6 +
 .../dto/convert/selector/CommonUpstream.java       |  38 +++---
 .../apache/shenyu/common/enums/RpcTypeEnum.java    |  12 +-
 .../dto/convert/selector/CommonUpstreamTest.java   |   4 +-
 13 files changed, 366 insertions(+), 177 deletions(-)

diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/ApiDocController.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/ApiDocController.java
index fe762e853..dae0a5614 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/ApiDocController.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/ApiDocController.java
@@ -21,7 +21,6 @@ import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import javax.annotation.Resource;
 import org.apache.shenyu.admin.config.properties.ApiDocProperties;
 import org.apache.shenyu.admin.model.bean.DocInfo;
 import org.apache.shenyu.admin.model.bean.DocItem;
@@ -31,7 +30,6 @@ import org.apache.shenyu.admin.model.vo.MenuDocItem;
 import org.apache.shenyu.admin.model.vo.MenuModule;
 import org.apache.shenyu.admin.model.vo.MenuProject;
 import org.apache.shenyu.admin.service.manager.DocManager;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -43,11 +41,15 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping("/apidoc")
 public class ApiDocController {
 
-    @Autowired
-    private DocManager docManager;
+    private final DocManager docManager;
 
-    @Resource
-    private ApiDocProperties apiDocProperties;
+    private final ApiDocProperties apiDocProperties;
+
+    public ApiDocController(final DocManager docManager,
+                            final ApiDocProperties apiDocProperties) {
+        this.docManager = docManager;
+        this.apiDocProperties = apiDocProperties;
+    }
 
     /**
      * Menu list of documents.
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/SandboxController.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/SandboxController.java
index 5bb8d5de2..2bacd3c20 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/SandboxController.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/controller/SandboxController.java
@@ -17,7 +17,6 @@
 
 package org.apache.shenyu.admin.controller;
 
-import com.google.common.collect.Maps;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
@@ -28,27 +27,32 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
 import okhttp3.Response;
 import okhttp3.ResponseBody;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.shenyu.admin.mapper.AppAuthMapper;
+import org.apache.shenyu.admin.model.dto.ProxyGatewayDTO;
 import org.apache.shenyu.admin.model.entity.AppAuthDO;
+import org.apache.shenyu.admin.service.AppAuthService;
+import org.apache.shenyu.admin.utils.Assert;
 import org.apache.shenyu.admin.utils.HttpUtils;
 import org.apache.shenyu.admin.utils.ShenyuSignatureUtils;
 import org.apache.shenyu.admin.utils.UploadUtils;
+import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.utils.JsonUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.util.UriComponents;
+import org.springframework.web.util.UriComponentsBuilder;
 import org.springframework.web.util.UriUtils;
 
 /**
@@ -61,74 +65,50 @@ public class SandboxController {
 
     private static final HttpUtils HTTP_UTILS = new HttpUtils();
 
-    @Resource
-    private AppAuthMapper appAuthMapper;
+    private final AppAuthService appAuthService;
+
+    public SandboxController(final AppAuthService appAuthService) {
+        this.appAuthService = appAuthService;
+    }
 
     /**
-     * proxyGateway.
+     * proxy Gateway.
      *
-     * @param gatewayUrl        gatewayUrl
-     * @param appKey            appKey
-     * @param method            method
-     * @param cookie            cookie
-     * @param bizParam          bizParam
-     * @param httpMethod        httpMethod
-     * @param request           request
-     * @param response          response
+     * @param proxyGatewayDTO proxyGatewayDTO
+     * @param request         request
+     * @param response        response
      * @throws IOException IOException
      */
-    @RequestMapping("/proxyGateway")
-    public void proxyGateway(
-        @RequestParam(required = false) final String gatewayUrl,
-        @RequestParam final String appKey,
-        @RequestParam final String method,
-        @RequestParam final String cookie,
-        @RequestParam final String bizParam,
-        @RequestParam(defaultValue = "get") final String httpMethod,
+    @PostMapping(path = "/proxyGateway")
+    public void proxyGateway(@RequestBody @Valid final ProxyGatewayDTO proxyGatewayDTO,
         final HttpServletRequest request,
         final HttpServletResponse response) throws IOException {
-
-        Assert.isTrue(StringUtils.isNotBlank(method), "method cannot be empty.");
-        Assert.isTrue(StringUtils.isNotBlank(gatewayUrl), "gatewayUrl cannot be empty.");
-        String gatewayUrlStr = gatewayUrl + method;
-
         // Public request parameters.
-        Map<String, String> params = new HashMap<String, String>();
+        Map<String, Object> reqParams = new HashMap<>();
         try {
-            String bizParamStr = StringEscapeUtils.escapeHtml4(bizParam);
-            Map<String, String> map = (Map) JsonUtils.toMap(bizParamStr);
-            LOG.info("bizParam toMap= {}", JsonUtils.toJson(map));
-            if (map != null) {
-                params.putAll(map);
+            String reqJson = JsonUtils.toJson(proxyGatewayDTO.getBizParam());
+            reqJson = StringEscapeUtils.escapeHtml4(reqJson);
+            Map<String, Object> reqMap = JsonUtils.toMap(reqJson);
+            LOG.info("bizParam toMap= {}", JsonUtils.toJson(reqMap));
+            if (Objects.nonNull(reqMap)) {
+                reqParams.putAll(reqMap);
             }
         } catch (Exception e) {
-            LOG.error("JsonUtils.toMap error={}", e);
+            LOG.error("proxyGateway JsonUtils.toMap error={}", e);
         }
 
-        String paramsQuery = buildParamQuery(params);
-
-        Collection<MultipartFile> uploadFiles = UploadUtils.getUploadFiles(request);
-        List<HttpUtils.UploadFile> files = uploadFiles.stream()
-            .map(multipartFile -> {
-                try {
-                    return new HttpUtils.UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
-                } catch (IOException e) {
-                    LOG.error("upload file fail", e);
-                    return null;
-                }
-            })
-            .filter(Objects::nonNull)
-            .collect(Collectors.toList());
-
         Map<String, String> header = new HashMap<>();
-        header.put("Cookie", cookie);
+        header.put("Cookie", proxyGatewayDTO.getCookie());
 
+        String appKey = proxyGatewayDTO.getAppKey();
+        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(proxyGatewayDTO.getRequestUrl()).build();
         String signContent = null;
         String sign = null;
         if (StringUtils.isNotEmpty(appKey)) {
             String timestamp = String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
             String secureKey = getSecureKey(appKey);
-            signContent = ShenyuSignatureUtils.getSignContent(secureKey, timestamp, method);
+            Assert.notBlack(secureKey, Constants.SIGN_APP_KEY_IS_NOT_EXIST);
+            signContent = ShenyuSignatureUtils.getSignContent(secureKey, timestamp, uriComponents.getPath());
             sign = ShenyuSignatureUtils.generateSign(signContent);
 
             header.put("timestamp", timestamp);
@@ -137,45 +117,39 @@ public class SandboxController {
             header.put("version", ShenyuSignatureUtils.VERSION);
         }
 
-        try {
-            Response resp = HTTP_UTILS.requestCall(gatewayUrlStr, params, header, HttpUtils.HTTPMethod.fromValue(httpMethod), files);
-            ResponseBody body = resp.body();
-            if (Objects.isNull(body)) {
-                return;
-            }
-            Map<String, List<String>> headersMap = resp.headers().toMultimap();
-            Map<String, String> targetHeaders = Maps.newHashMapWithExpectedSize(headersMap.size());
-            headersMap.forEach((key, value) -> {
-                String headerValue = String.join(",", value);
-                response.setHeader(key, headerValue);
-                targetHeaders.put(key, headerValue);
-            });
-            response.addHeader("response-headers", JsonUtils.toJson(targetHeaders));
-            response.addHeader("sendbox-params", UriUtils.encode(paramsQuery, StandardCharsets.UTF_8));
-            response.addHeader("sendbox-beforesign", UriUtils.encode(signContent, StandardCharsets.UTF_8));
-            response.addHeader("sendbox-sign", UriUtils.encode(sign, StandardCharsets.UTF_8));
-            IOUtils.copy(body.byteStream(), response.getOutputStream());
-            response.flushBuffer();
-        } catch (Exception e) {
-            LOG.error("request error", e);
-            throw new RuntimeException(e.getMessage());
+        List<HttpUtils.UploadFile> files = uploadFiles(request);
+        Response resp = HTTP_UTILS.requestCall(uriComponents.toUriString(), reqParams, header, HttpUtils.HTTPMethod.fromValue(proxyGatewayDTO.getHttpMethod()), files);
+        ResponseBody body = resp.body();
+        if (Objects.isNull(body)) {
+            return;
         }
+        if (StringUtils.isNotEmpty(appKey)) {
+            response.addHeader("sandbox-beforesign", UriUtils.encode(signContent, StandardCharsets.UTF_8));
+            response.addHeader("sandbox-sign", UriUtils.encode(sign, StandardCharsets.UTF_8));
+        }
+        IOUtils.copy(body.byteStream(), response.getOutputStream());
+        response.flushBuffer();
     }
 
     private String getSecureKey(final String appKey) {
-        AppAuthDO appAuthDO = appAuthMapper.findByAppKey(appKey);
-        if (Objects.isNull(appAuthDO) || StringUtils.isEmpty(appAuthDO.getAppSecret())) {
-            throw new RuntimeException("security key not found.");
-        }
-        return appAuthDO.getAppSecret();
+        AppAuthDO appAuthDO = appAuthService.findByAppKey(appKey);
+        return Objects.nonNull(appAuthDO) ? appAuthDO.getAppSecret() : null;
     }
 
-    protected String buildParamQuery(final Map<String, String> params) {
-        StringBuilder sb = new StringBuilder();
-        for (Map.Entry<String, String> entry : params.entrySet()) {
-            sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
-        }
-        return sb.substring(1);
+    private List<HttpUtils.UploadFile> uploadFiles(final HttpServletRequest request) {
+        Collection<MultipartFile> uploadFiles = UploadUtils.getUploadFiles(request);
+        List<HttpUtils.UploadFile> files = uploadFiles.stream()
+            .map(multipartFile -> {
+                try {
+                    return new HttpUtils.UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
+                } catch (IOException e) {
+                    LOG.error("upload file fail", e);
+                    return null;
+                }
+            })
+            .filter(Objects::nonNull)
+            .collect(Collectors.toList());
+        return files;
     }
 
 }
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/ProxyGatewayDTO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/ProxyGatewayDTO.java
new file mode 100644
index 000000000..6d6c5244c
--- /dev/null
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/dto/ProxyGatewayDTO.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.admin.model.dto;
+
+/**
+ * this User Role Dto.
+ */
+public class ProxyGatewayDTO {
+
+    /**
+     * request Url.
+     */
+    private String requestUrl;
+
+    /**
+     * request appKey.
+     */
+    private String appKey;
+
+    /**
+     * request cookie.
+     */
+    private String cookie;
+
+    /**
+     * request bizParam.
+     */
+    private Object bizParam;
+
+    /**
+     * request httpMethod.
+     */
+    private String httpMethod = "get";
+
+    /**
+     * getRequestUrl.
+     *
+     * @return request Url
+     */
+    public String getRequestUrl() {
+        return requestUrl;
+    }
+
+    /**
+     * setRequestUrl.
+     *
+     * @param requestUrl requestUrl
+     */
+    public void setRequestUrl(final String requestUrl) {
+        this.requestUrl = requestUrl;
+    }
+
+    /**
+     * getAppKey.
+     *
+     * @return appKey
+     */
+    public String getAppKey() {
+        return appKey;
+    }
+
+    /**
+     * setAppKey.
+     *
+     * @param appKey appKey
+     */
+    public void setAppKey(final String appKey) {
+        this.appKey = appKey;
+    }
+
+    /**
+     * getCookie.
+     *
+     * @return cookie
+     */
+    public String getCookie() {
+        return cookie;
+    }
+
+    /**
+     * setCookie.
+     *
+     * @param cookie cookie
+     */
+    public void setCookie(final String cookie) {
+        this.cookie = cookie;
+    }
+
+    /**
+     * getBizParam.
+     *
+     * @return bizParam
+     */
+    public Object getBizParam() {
+        return bizParam;
+    }
+
+    /**
+     * setBizParam.
+     *
+     * @param bizParam bizParam
+     */
+    public void setBizParam(final Object bizParam) {
+        this.bizParam = bizParam;
+    }
+
+    /**
+     * getHttpMethod.
+     *
+     * @return httpMethod
+     */
+    public String getHttpMethod() {
+        return httpMethod;
+    }
+
+    /**
+     * httpMethod.
+     *
+     * @param httpMethod httpMethod
+     */
+    public void setHttpMethod(final String httpMethod) {
+        this.httpMethod = httpMethod;
+    }
+}
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/query/SelectorQuery.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/query/SelectorQuery.java
index b15a6409a..12177eeda 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/query/SelectorQuery.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/query/SelectorQuery.java
@@ -17,6 +17,7 @@
 
 package org.apache.shenyu.admin.model.query;
 
+import java.util.List;
 import org.apache.shenyu.admin.model.page.PageParameter;
 
 import java.util.Objects;
@@ -33,6 +34,11 @@ public class SelectorQuery extends FilterQuery {
      */
     private String pluginId;
 
+    /**
+     * plugin ids.
+     */
+    private List<String> pluginIds;
+
     /**
      * selector name.
      */
@@ -52,6 +58,12 @@ public class SelectorQuery extends FilterQuery {
         this.pageParameter = pageParameter;
     }
 
+    public SelectorQuery(final List<String> pluginIds, final String name, final PageParameter pageParameter) {
+        this.pluginIds = pluginIds;
+        this.name = name;
+        this.pageParameter = pageParameter;
+    }
+
     /**
      * Gets the value of pluginId.
      *
@@ -70,6 +82,24 @@ public class SelectorQuery extends FilterQuery {
         this.pluginId = pluginId;
     }
 
+    /**
+     * Gets the value of pluginIds.
+     *
+     * @return the value of pluginIds
+     */
+    public List<String> getPluginIds() {
+        return pluginIds;
+    }
+
+    /**
+     * Sets the pluginIds.
+     *
+     * @param pluginIds pluginIds
+     */
+    public void setPluginIds(final List<String> pluginIds) {
+        this.pluginIds = pluginIds;
+    }
+
     /**
      * Gets the value of name.
      *
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/AppAuthService.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/AppAuthService.java
index f6c20bd56..063a06abb 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/AppAuthService.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/AppAuthService.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.admin.service;
 import org.apache.shenyu.admin.model.dto.AppAuthDTO;
 import org.apache.shenyu.admin.model.dto.AuthApplyDTO;
 import org.apache.shenyu.admin.model.dto.AuthPathWarpDTO;
+import org.apache.shenyu.admin.model.entity.AppAuthDO;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.query.AppAuthQuery;
 import org.apache.shenyu.admin.model.result.ShenyuAdminResult;
@@ -136,6 +137,14 @@ public interface AppAuthService extends PageService<AppAuthQuery, AppAuthVO> {
      */
     ShenyuAdminResult updateAppSecretByAppKey(String appKey, String appSecret);
 
+    /**
+     * Find by app key app auth do.
+     *
+     * @param appKey the app key
+     * @return the app auth do
+     */
+    AppAuthDO findByAppKey(String appKey);
+
 
     /**
      * Sync data shenyu result.
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
index 5eb37d4c5..e632b708a 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AppAuthServiceImpl.java
@@ -85,12 +85,12 @@ public class AppAuthServiceImpl implements AppAuthService {
         this.authParamMapper = authParamMapper;
         this.authPathMapper = authPathMapper;
     }
-    
+
     @Override
     public List<AppAuthVO> searchByCondition(final AppAuthQuery condition) {
         return appAuthMapper.selectByCondition(condition);
     }
-    
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public ShenyuAdminResult applyCreate(final AuthApplyDTO authApplyDTO) {
@@ -421,6 +421,11 @@ public class AppAuthServiceImpl implements AppAuthService {
         return ShenyuAdminResult.success(appAuthMapper.updateAppSecretByAppKey(appKey, appSecret));
     }
 
+    @Override
+    public AppAuthDO findByAppKey(final String appKey) {
+        return appAuthMapper.findByAppKey(appKey);
+    }
+
     private AppAuthData buildByEntity(final AppAuthDO appAuthDO) {
         AppAuthData data = AppAuthData.builder()
                 .appKey(appAuthDO.getAppKey())
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
index 6017726e4..97b5907bf 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/LoadServiceDocEntryImpl.java
@@ -17,32 +17,38 @@
 
 package org.apache.shenyu.admin.service.manager.impl;
 
+import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
-import javax.annotation.Resource;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.admin.mapper.PluginMapper;
 import org.apache.shenyu.admin.model.bean.UpstreamInstance;
+import org.apache.shenyu.admin.model.entity.PluginDO;
 import org.apache.shenyu.admin.model.page.CommonPager;
 import org.apache.shenyu.admin.model.page.PageParameter;
 import org.apache.shenyu.admin.model.query.SelectorQuery;
 import org.apache.shenyu.admin.model.vo.SelectorVO;
 import org.apache.shenyu.admin.service.SelectorService;
+import org.apache.shenyu.admin.service.converter.SelectorHandleConverterFactor;
 import org.apache.shenyu.admin.service.manager.LoadServiceDocEntry;
+import org.apache.shenyu.admin.service.manager.ServiceDocManager;
 import org.apache.shenyu.common.dto.SelectorData;
 import org.apache.shenyu.common.dto.convert.selector.CommonUpstream;
 import org.apache.shenyu.common.enums.DataEventTypeEnum;
-import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.JsonUtils;
+import org.apache.shenyu.common.utils.PluginNameAdapter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
 
 /**
  * Load Service Doc Entry.
@@ -51,11 +57,25 @@ import org.springframework.util.CollectionUtils;
 public class LoadServiceDocEntryImpl implements LoadServiceDocEntry {
     private static final Logger LOG = LoggerFactory.getLogger(LoadServiceDocEntryImpl.class);
 
-    @Resource
-    private SelectorService selectorService;
+    private static Map<String, String> supportSwaggePluginMap = Collections.EMPTY_MAP;
 
-    @Resource
-    private ServiceDocManagerImpl serviceDocManager;
+    private final SelectorService selectorService;
+
+    private final SelectorHandleConverterFactor converterFactor;
+
+    private final PluginMapper pluginMapper;
+
+    private final ServiceDocManager serviceDocManager;
+
+    public LoadServiceDocEntryImpl(final SelectorService selectorService,
+                                   final SelectorHandleConverterFactor converterFactor,
+                                   final PluginMapper pluginMapper,
+                                   final ServiceDocManager serviceDocManager) {
+        this.selectorService = selectorService;
+        this.converterFactor = converterFactor;
+        this.pluginMapper = pluginMapper;
+        this.serviceDocManager = serviceDocManager;
+    }
 
     @Override
     public synchronized void loadApiDocument() {
@@ -102,13 +122,17 @@ public class LoadServiceDocEntryImpl implements LoadServiceDocEntry {
      * @return List
      */
     private List<UpstreamInstance> getAllClusterLastUpdateInstanceList() {
-        List<SelectorVO> clusterList = null;
-        try {
-            CommonPager<SelectorVO> commonPager = selectorService.listByPage(new SelectorQuery("5", null, new PageParameter(1, Integer.MAX_VALUE)));
-            clusterList = commonPager.getDataList();
-        } catch (Exception e) {
-            LOG.error("getAllClusterLastUpdateInstanceList fail. error={}", e);
+        List<String> pluginNames = new ArrayList<>();
+        RpcTypeEnum.acquireSupportSwaggers().forEach(rpcTypeEnum -> pluginNames.add(PluginNameAdapter.rpcTypeAdapter(rpcTypeEnum.getName())));
+        final List<PluginDO> pluginDOList = pluginMapper.selectByNames(pluginNames);
+        if (CollectionUtils.isEmpty(pluginDOList)) {
+            return Collections.EMPTY_LIST;
         }
+        supportSwaggePluginMap = pluginDOList.stream().filter(Objects::nonNull)
+            .collect(Collectors.toMap(PluginDO::getId, PluginDO::getName, (value1, value2) -> value1));
+
+        CommonPager<SelectorVO> commonPager = selectorService.listByPage(new SelectorQuery(Lists.newArrayList(supportSwaggePluginMap.keySet()), null, new PageParameter(1, Integer.MAX_VALUE)));
+        List<SelectorVO> clusterList = commonPager.getDataList();
         if (CollectionUtils.isEmpty(clusterList)) {
             LOG.info("getAllClusterLastUpdateInstanceList, Not loaded into available backend services.");
             return Collections.EMPTY_LIST;
@@ -122,77 +146,68 @@ public class LoadServiceDocEntryImpl implements LoadServiceDocEntry {
     }
 
     private UpstreamInstance getClusterLastUpdateInstance(final SelectorVO selectorVO) {
-        List<UpstreamInstance> allInstances = null;
-        // Get service instance.
-        String handle = selectorVO.getHandle();
-        if (StringUtils.isNotEmpty(handle)) {
-            allInstances = new ArrayList<>();
-            try {
-                List<CommonUpstream> upstreamList = this.convert(handle);
-                for (CommonUpstream upstream : upstreamList) {
-                    String[] upstreamUrlArr = upstream.getUpstreamUrl().split(":");
-                    UpstreamInstance instance = new UpstreamInstance();
-                    instance.setContextPath(selectorVO.getName());
-                    instance.setIp(upstreamUrlArr[0]);
-                    instance.setPort(Integer.parseInt(upstreamUrlArr[1]));
-                    instance.setEnabled(selectorVO.getEnabled());
-                    instance.setHealthy(true);
-                    instance.setStartupTime(upstream.getTimestamp());
-                    allInstances.add(instance);
-                }
-            } catch (Exception e) {
-                LOG.error("Error getting cluster instance list. serviceName={} error={}", selectorVO.getName(), e);
-                return null;
-            }
+        List<UpstreamInstance> allInstances = getInstances(selectorVO.getPluginId(), selectorVO.getHandle(), selectorVO.getName(), selectorVO.getEnabled());
+        if (CollectionUtils.isEmpty(allInstances)) {
+            return null;
         }
-
         return getClusterLastUpdateInstance(allInstances);
     }
 
     private UpstreamInstance getClusterLastUpdateInstance(final SelectorData selectorData) {
-        if (!selectorData.getPluginId().equals("5")) {
+        if (!supportSwaggePluginMap.keySet().contains(selectorData.getPluginId())) {
             LOG.info("getClusterLastUpdateInstance. pluginNae={} does not support pulling API documents.", selectorData.getPluginName());
             return null;
         }
+        List<UpstreamInstance> allInstances = getInstances(selectorData.getPluginId(), selectorData.getHandle(), selectorData.getName(), selectorData.getEnabled());
+        if (Objects.isNull(allInstances)) {
+            return null;
+        }
+        return getClusterLastUpdateInstance(allInstances);
+    }
+
+    private UpstreamInstance getClusterLastUpdateInstance(final List<UpstreamInstance> allInstances) {
+        if (CollectionUtils.isEmpty(allInstances)) {
+            return null;
+        }
+        return allInstances.stream()
+            .filter(UpstreamInstance::isHealthy)
+            .filter(Objects::nonNull)
+            .max(Comparator.comparing(UpstreamInstance::getStartupTime))
+            .orElse(null);
+    }
+
+    private List<UpstreamInstance> getInstances(final String pluginId, final String handle, final String contextPath,
+        final boolean enabled) {
         List<UpstreamInstance> allInstances = null;
         // Get service instance.
-        String handle = selectorData.getHandle();
         if (StringUtils.isNotEmpty(handle)) {
             allInstances = new ArrayList<>();
             try {
-                List<CommonUpstream> upstreamList = this.convert(handle);
+                List<CommonUpstream> upstreamList = this.convert(pluginId, handle);
                 for (CommonUpstream upstream : upstreamList) {
-                    String[] upstreamUrlArr = upstream.getUpstreamUrl().split(":");
                     UpstreamInstance instance = new UpstreamInstance();
-                    instance.setContextPath(selectorData.getName());
+                    instance.setContextPath(contextPath);
+                    String[] upstreamUrlArr = upstream.getUpstreamUrl().split(":");
                     instance.setIp(upstreamUrlArr[0]);
-                    instance.setPort(Integer.parseInt(upstreamUrlArr[1]));
-                    instance.setEnabled(selectorData.getEnabled());
+                    instance.setPort(upstreamUrlArr.length == 1 ? 80 : Integer.parseInt(upstreamUrlArr[1]));
+                    instance.setEnabled(enabled);
                     instance.setHealthy(true);
                     instance.setStartupTime(upstream.getTimestamp());
                     allInstances.add(instance);
                 }
             } catch (Exception e) {
-                LOG.error("Error getting cluster instance list. serviceName={} error={}", selectorData.getName(), e);
+                LOG.error("Error getting cluster instance list. contextPath={} error={}", contextPath, e);
                 return null;
             }
         }
-        return getClusterLastUpdateInstance(allInstances);
-    }
-
-    private UpstreamInstance getClusterLastUpdateInstance(final List<UpstreamInstance> allInstances) {
-        if (CollectionUtils.isEmpty(allInstances)) {
-            return null;
-        }
-        return allInstances.stream()
-            .filter(UpstreamInstance::isHealthy)
-            .filter(Objects::nonNull)
-            .max(Comparator.comparing(UpstreamInstance::getStartupTime))
-            .orElse(null);
+        return allInstances;
     }
 
-    private List<CommonUpstream> convert(final String handle) {
-        return GsonUtils.getInstance().fromList(handle, CommonUpstream.class);
+    private List<CommonUpstream> convert(final String pluginId, final String handle) {
+        String pluginName = supportSwaggePluginMap.get(pluginId);
+        return converterFactor.newInstance(pluginName).convertUpstream(handle)
+            .stream().filter(upstream -> upstream.isStatus())
+            .collect(Collectors.toList());
     }
 
 }
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/SwaggerDocParser.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/SwaggerDocParser.java
index 238a53cbc..4685cf733 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/SwaggerDocParser.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/manager/impl/SwaggerDocParser.java
@@ -170,12 +170,11 @@ public class SwaggerDocParser implements DocParser {
     }
 
     protected String buildModuleName(final JsonObject docInfo, final JsonObject docRoot, final String basePath) {
-        final String title = Optional.ofNullable(docRoot.getAsJsonObject("info")).map(jsonObject -> jsonObject.get("title").getAsString()).orElse(basePath);
         JsonArray tags = docInfo.getAsJsonArray("tags");
         if (Objects.nonNull(tags) && tags.size() > 0) {
             return tags.get(0).getAsString();
         }
-        return title;
+        return Optional.ofNullable(docRoot.getAsJsonObject("info")).map(jsonObject -> jsonObject.get("title").getAsString()).orElse(basePath);
     }
 
     protected List<DocParameter> buildRequestParameterList(final JsonObject docInfo, final JsonObject docRoot) {
diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/CommonUpstreamUtils.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/CommonUpstreamUtils.java
index b54e95ed3..be6cc842b 100644
--- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/CommonUpstreamUtils.java
+++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/CommonUpstreamUtils.java
@@ -171,7 +171,7 @@ public class CommonUpstreamUtils {
         return Optional.ofNullable(upstreamList)
                 .orElse(Collections.emptyList())
                 .stream()
-                .map(upstream -> new CommonUpstream(upstream.getProtocol(), upstream.getUpstreamHost(), upstream.getUpstreamUrl(), upstream.isStatus()))
+                .map(upstream -> new CommonUpstream(upstream.getProtocol(), upstream.getUpstreamHost(), upstream.getUpstreamUrl(), upstream.isStatus(), upstream.getTimestamp()))
                 .collect(Collectors.toList());
     }
     
diff --git a/shenyu-admin/src/main/resources/mappers/selector-sqlmap.xml b/shenyu-admin/src/main/resources/mappers/selector-sqlmap.xml
index 9801880b8..100d6f6e9 100644
--- a/shenyu-admin/src/main/resources/mappers/selector-sqlmap.xml
+++ b/shenyu-admin/src/main/resources/mappers/selector-sqlmap.xml
@@ -89,6 +89,12 @@
             <if test="pluginId != null">
                 plugin_id = #{pluginId, jdbcType=VARCHAR}
             </if>
+            <if test="pluginIds != null and pluginIds.size > 0">
+                AND plugin_id IN
+                <foreach item="pluginId" collection="pluginIds" open="(" separator="," close=")">
+                    #{pluginId, jdbcType=VARCHAR}
+                </foreach>
+            </if>
             <if test="name != null and name != ''">
                 <bind name="nameLike" value="('%' + name + '%')"/>
                  AND name LIKE #{nameLike, jdbcType=VARCHAR}
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstream.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstream.java
index e08822782..17bf60172 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstream.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstream.java
@@ -23,7 +23,7 @@ import java.util.Objects;
  * this is common upstream.
  */
 public class CommonUpstream {
-    
+
     /**
      * this is http protocol.
      */
@@ -38,24 +38,24 @@ public class CommonUpstream {
      * url.
      */
     private String upstreamUrl;
-    
+
     /**
      * false close/ true open.
      */
     private boolean status = true;
-    
+
     /**
      * startup time.
      */
     private long timestamp;
-    
+
     /**
      * Instantiates a new Common upstream.
      */
     public CommonUpstream() {
-        
+
     }
-    
+
     /**
      * Instantiates a new Common upstream.
      *
@@ -63,14 +63,16 @@ public class CommonUpstream {
      * @param upstreamHost the upstream host
      * @param upstreamUrl the upstream url
      * @param status the upstream status
+     * @param timestamp the upstream timestamp
      */
-    public CommonUpstream(final String protocol, final String upstreamHost, final String upstreamUrl, final boolean status) {
+    public CommonUpstream(final String protocol, final String upstreamHost, final String upstreamUrl, final boolean status, final long timestamp) {
         this.protocol = protocol;
         this.upstreamHost = upstreamHost;
         this.upstreamUrl = upstreamUrl;
         this.status = status;
+        this.timestamp = timestamp;
     }
-    
+
     /**
      * get upstreamHost.
      *
@@ -79,7 +81,7 @@ public class CommonUpstream {
     public String getUpstreamHost() {
         return upstreamHost;
     }
-    
+
     /**
      * set upstreamHost.
      *
@@ -88,7 +90,7 @@ public class CommonUpstream {
     public void setUpstreamHost(final String upstreamHost) {
         this.upstreamHost = upstreamHost;
     }
-    
+
     /**
      * get protocol.
      *
@@ -97,7 +99,7 @@ public class CommonUpstream {
     public String getProtocol() {
         return protocol;
     }
-    
+
     /**
      * set protocol.
      *
@@ -106,7 +108,7 @@ public class CommonUpstream {
     public void setProtocol(final String protocol) {
         this.protocol = protocol;
     }
-    
+
     /**
      * get upstreamUrl.
      *
@@ -115,7 +117,7 @@ public class CommonUpstream {
     public String getUpstreamUrl() {
         return upstreamUrl;
     }
-    
+
     /**
      * set upstreamUrl.
      *
@@ -124,7 +126,7 @@ public class CommonUpstream {
     public void setUpstreamUrl(final String upstreamUrl) {
         this.upstreamUrl = upstreamUrl;
     }
-    
+
     /**
      * get status.
      *
@@ -133,7 +135,7 @@ public class CommonUpstream {
     public boolean isStatus() {
         return status;
     }
-    
+
     /**
      * set status.
      *
@@ -142,7 +144,7 @@ public class CommonUpstream {
     public void setStatus(final boolean status) {
         this.status = status;
     }
-    
+
     /**
      * get timestamp.
      *
@@ -151,7 +153,7 @@ public class CommonUpstream {
     public long getTimestamp() {
         return timestamp;
     }
-    
+
     /**
      * set timestamp.
      *
@@ -160,7 +162,7 @@ public class CommonUpstream {
     public void setTimestamp(final long timestamp) {
         this.timestamp = timestamp;
     }
-    
+
     /**
      * Default status boolean.
      *
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RpcTypeEnum.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RpcTypeEnum.java
index e104148d4..572aee40f 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RpcTypeEnum.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RpcTypeEnum.java
@@ -130,6 +130,14 @@ public enum RpcTypeEnum {
         return Arrays.asList(RpcTypeEnum.HTTP, RpcTypeEnum.DUBBO, RpcTypeEnum.GRPC, RpcTypeEnum.SPRING_CLOUD, RpcTypeEnum.SOFA, RpcTypeEnum.TARS, RpcTypeEnum.MOTAN);
     }
 
+    /**
+     * acquire operator support swagger type.
+     * @return operator support.
+     */
+    public static List<RpcTypeEnum> acquireSupportSwaggers() {
+        return Arrays.asList(RpcTypeEnum.HTTP, RpcTypeEnum.SPRING_CLOUD);
+    }
+
     /**
      * acquireByName.
      *
@@ -138,7 +146,7 @@ public enum RpcTypeEnum {
      */
     public static RpcTypeEnum acquireByName(final String name) {
         return Arrays.stream(RpcTypeEnum.values())
-                .filter(e -> e.support && e.name.equals(name)).findFirst()
-                .orElseThrow(() -> new ShenyuException(String.format(" this rpc type can not support %s", name)));
+            .filter(e -> e.support && e.name.equals(name)).findFirst()
+            .orElseThrow(() -> new ShenyuException(String.format(" this rpc type can not support %s", name)));
     }
 }
diff --git a/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstreamTest.java b/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstreamTest.java
index c928fb8c3..83c13fd52 100644
--- a/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstreamTest.java
+++ b/shenyu-common/src/test/java/org/apache/shenyu/common/dto/convert/selector/CommonUpstreamTest.java
@@ -47,8 +47,8 @@ public class CommonUpstreamTest {
     
     @Test
     public void testEqualsAndHashCode() {
-        CommonUpstream upstream1 = new CommonUpstream("protocol", "host", "url", true);
-        CommonUpstream upstream2 = new CommonUpstream("protocol", "host", "url", true);
+        CommonUpstream upstream1 = new CommonUpstream("protocol", "host", "url", true, System.currentTimeMillis());
+        CommonUpstream upstream2 = new CommonUpstream("protocol", "host", "url", true, System.currentTimeMillis());
         
         assertThat(ImmutableSet.of(upstream1, upstream2), hasSize(1));
     }