dubbo文档优化

This commit is contained in:
暮光:城中城
2020-11-18 00:37:26 +08:00
parent e0289aa247
commit 95ec165d49
40 changed files with 2081 additions and 1127 deletions

View File

@@ -1,44 +1,32 @@
package com.zyplayer.doc.dubbo.controller;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.core.annotation.AuthMan;
import com.zyplayer.doc.core.json.DocResponseJson;
import com.zyplayer.doc.dubbo.controller.param.DubboRequestParam;
import com.zyplayer.doc.dubbo.controller.vo.DubboInfoVo;
import com.zyplayer.doc.dubbo.controller.vo.NacosServiceInfoVo;
import com.zyplayer.doc.dubbo.controller.vo.NacosServiceListVo;
import com.zyplayer.doc.dubbo.framework.bean.DubboDocInfo;
import com.zyplayer.doc.dubbo.framework.bean.DubboInfo;
import com.zyplayer.doc.dubbo.framework.bean.NacosDubboInfo;
import com.zyplayer.doc.dubbo.framework.bean.ReferenceConfigHolder;
import com.zyplayer.doc.dubbo.framework.constant.DubboDocConst;
import com.zyplayer.doc.dubbo.framework.constant.StorageKeys;
import com.zyplayer.doc.dubbo.framework.service.ClassLoadService;
import com.zyplayer.doc.dubbo.framework.service.MgDubboStorageService;
import com.zyplayer.doc.dubbo.framework.service.NacosDocService;
import com.zyplayer.doc.dubbo.framework.service.ZookeeperDocService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
import org.apache.dubbo.metadata.definition.model.MethodDefinition;
import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
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 javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -56,53 +44,17 @@ import java.util.stream.Collectors;
public class DubboController {
private static Logger logger = LoggerFactory.getLogger(DubboController.class);
private final static String DEFAULT_ROOT = "dubbo";
private final static String METADATA_NODE_NAME = "service.data";
private String root;
@Value("${zyplayer.doc.dubbo.doc-lib-path}")
private String zyplayerDocDubboLibPath;
@Value("${zyplayer.doc.dubbo.zookeeper.url:}")
private String serviceZookeeperUrl;
@Value("${zyplayer.doc.dubbo.zookeeper.metadata-url:}")
private String metadataZookeeperUrl;
@Value("${zyplayer.doc.dubbo.nacos.url:}")
private String nacosUrl;
// @Value("${zyplayer.doc.dubbo.nacos.service:}")
// private String nacosService;
@Resource
private MgDubboStorageService mgDubboStorageService;
private CuratorFramework serverClient;
private CuratorFramework metadataClient;
private void initServerClient() {
if (serverClient == null && StringUtils.isNotBlank(serviceZookeeperUrl)) {
synchronized (DEFAULT_ROOT) {
if (serverClient == null) {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
serverClient = CuratorFrameworkFactory.newClient(serviceZookeeperUrl, retryPolicy);
serverClient.start();
}
}
}
}
private void initMetadataClient() {
if (metadataClient == null && StringUtils.isNotBlank(metadataZookeeperUrl)) {
synchronized (DEFAULT_ROOT) {
if (metadataClient == null) {
URL url = UrlUtils.parseURL(metadataZookeeperUrl, Collections.emptyMap());
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(Constants.PATH_SEPARATOR)) {
group = Constants.PATH_SEPARATOR + group;
}
this.root = group;
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
metadataClient = CuratorFrameworkFactory.newClient(metadataZookeeperUrl, retryPolicy);
metadataClient.start();
}
}
}
}
@Resource
private ZookeeperDocService zookeeperDocService;
@Resource
private NacosDocService nacosDocService;
@Resource
ClassLoadService classLoadService;
/**
* 重新获取所有的服务列表
@@ -111,17 +63,17 @@ public class DubboController {
* @since 2019年2月10日
**/
@PostMapping(value = "/reloadService")
public DocResponseJson loadService() throws Exception {
public DocResponseJson loadService() {
List<DubboInfo> providerList;
try {
if (StringUtils.isBlank(serviceZookeeperUrl)) {
if (StringUtils.isBlank(nacosUrl)) {// || StringUtils.isBlank(nacosService)) {
if (!zookeeperDocService.isEnable()) {
if (!nacosDocService.isEnable()) {
return DocResponseJson.warn("zyplayer.doc.dubbo.zookeeper.url、zyplayer.doc.dubbo.nacos.url 参数均未配置");
}
logger.info("zookeeper参数未配置使用nacos配置");
providerList = this.getDubboInfoByNacos();
providerList = nacosDocService.getDubboInfoByNacos();
} else {
providerList = this.getDubboInfoByZookeeper();
providerList = zookeeperDocService.getDubboInfoByZookeeper();
}
mgDubboStorageService.put(StorageKeys.DUBBO_SERVICE_LIST, JSON.toJSONString(providerList));
} catch (Exception e) {
@@ -143,6 +95,8 @@ public class DubboController {
dubboNodeInfo.setIp(param.getIp());
dubboNodeInfo.setPort(param.getPort());
dubboNodeInfo.setInterfaceX(param.getService());
dubboNodeInfo.setVersion(param.getVersion());
dubboNodeInfo.setGroup(param.getGroup());
String paramTypeStr = Optional.ofNullable(param.getParamTypes()).orElse("");
String paramsStr = Optional.ofNullable(param.getParams()).orElse("");
List<String> typeList = JSON.parseArray(paramTypeStr, String.class);
@@ -155,7 +109,7 @@ public class DubboController {
try {
if (typeStr.endsWith("[]")) {
String type = typeStr.substring(0, typeStr.length() - 2);
Class<?> aClass = Class.forName(type);
Class<?> aClass = classLoadService.loadClass(type);
List<?> objects = JSON.parseArray(paramStr, aClass);
queryTypeList.add(typeStr);
queryParamList.add(objects);
@@ -164,13 +118,13 @@ public class DubboController {
Matcher matcher = pattern.matcher(typeStr);
if (matcher.find()) {
String group = matcher.group(1);
Class<?> aClass = Class.forName(group);
Class<?> aClass = classLoadService.loadClass(group);
List<?> objects = JSON.parseArray(paramStr, aClass);
queryParamList.add(objects);
queryTypeList.add("java.util.List");
}
} else {
Class<?> aClass = Class.forName(typeStr);
Class<?> aClass = classLoadService.loadClass(typeStr);
Object object = JSON.parseObject(paramStr, aClass);
queryParamList.add(object);
queryTypeList.add(typeStr);
@@ -182,13 +136,16 @@ public class DubboController {
queryTypeList.add(typeStr);
}
}
GenericService bean = ReferenceConfigHolder.getBean(dubboNodeInfo);
try {
GenericService bean = ReferenceConfigHolder.getBean(dubboNodeInfo);
if (bean == null) {
return DocResponseJson.warn("操作失败获取dubbo服务失败");
}
Object result = bean.$invoke(param.getMethod(), queryTypeList.toArray(new String[]{}), queryParamList.toArray());
return DocResponseJson.ok(result);
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("请求失败" + e.getMessage());
return DocResponseJson.warn("操作失败" + e.getMessage());
}
}
@@ -224,9 +181,9 @@ public class DubboController {
**/
@PostMapping(value = "/findDocInfo")
public DocResponseJson findDocInfo(DubboRequestParam param) {
DubboDocInfo definition = this.getDefinitionByJar(param);
DubboDocInfo definition = zookeeperDocService.getDefinitionByJar(param);
if (definition == null) {
definition = this.getDefinitionByMetadata(param);
definition = zookeeperDocService.getDefinitionByMetadata(param);
}
if (definition == null) {
return DocResponseJson.warn("未找到指定类请引入相关包或开启metadata类名" + param.getService());
@@ -298,173 +255,36 @@ public class DubboController {
}
/**
* 通过nacos方式获取所有服务
* 上传文档jar
*
* @author 暮光:城中城
* @since 2019年2月10
* @since 2020年10月08
**/
private List<DubboInfo> getDubboInfoByNacos() {
List<DubboInfo> providerList = new LinkedList<>();
// 获取所有的服务列表
String serviceListStr = HttpUtil.get(nacosUrl + "/v1/ns/catalog/services?withInstances=false&pageNo=1&pageSize=100000");
NacosServiceInfoVo nacosServiceInfoVo = JSON.parseObject(serviceListStr, NacosServiceInfoVo.class);
if (nacosServiceInfoVo == null || nacosServiceInfoVo.getServiceList().isEmpty()) {
return providerList;
@PostMapping(value = "/uploadDocJar")
public DocResponseJson uploadDocJar(@RequestParam("file") MultipartFile file) {
File newFileDir = new File(zyplayerDocDubboLibPath);
if (!newFileDir.exists() && !newFileDir.mkdirs()) {
return DocResponseJson.warn("创建文件夹失败");
}
for (NacosServiceListVo service : nacosServiceInfoVo.getServiceList()) {
String serviceName = service.getName();
String resultStr = HttpUtil.get(nacosUrl + "/v1/ns/instance/list?serviceName=" + serviceName);
NacosDubboInfo dubboInstance = JSON.parseObject(resultStr, NacosDubboInfo.class);
List<NacosDubboInfo.HostsBean> hosts = dubboInstance.getHosts();
DubboInfo dubboInfo = new DubboInfo();
List<DubboInfo.DubboNodeInfo> nodeList = new LinkedList<>();
for (NacosDubboInfo.HostsBean host : hosts) {
DubboInfo.DubboNodeInfo dubboNodeInfo = new DubboInfo.DubboNodeInfo();
dubboNodeInfo.setIp(host.getIp());
dubboNodeInfo.setPort(host.getPort());
dubboNodeInfo.setInterfaceX(host.getMetadata().getInterfaceX());
dubboNodeInfo.setMethods(host.getMetadata().getMethods().split(","));
dubboNodeInfo.setApplication(host.getMetadata().getApplication());
nodeList.add(dubboNodeInfo);
}
if (serviceName.contains(":")) {
serviceName = serviceName.substring(serviceName.indexOf(":") + 1);
}
dubboInfo.setInterfaceX(serviceName);
dubboInfo.setNodeList(nodeList);
providerList.add(dubboInfo);
String fileSuffix = null;
String fileName = file.getOriginalFilename();
if (fileName != null) {
fileSuffix = fileName.substring(fileName.lastIndexOf("."));
}
return providerList;
}
/**
* 通过Zookeeper方式获取所有服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
private List<DubboInfo> getDubboInfoByZookeeper() throws Exception {
this.initServerClient();
List<String> dubboList = serverClient.getChildren().forPath("/dubbo");
if (dubboList == null || dubboList.isEmpty()) {
return Collections.emptyList();
if (!Objects.equals(".jar", fileSuffix)) {
return DocResponseJson.warn("仅支持jar后缀的文件格式上传");
}
List<DubboInfo> providerList = new LinkedList<>();
for (String dubboStr : dubboList) {
String path = "/dubbo/" + dubboStr + "/providers";
if (serverClient.checkExists().forPath(path) == null) {
continue;
}
List<String> providers = serverClient.getChildren().forPath(path);
List<DubboInfo.DubboNodeInfo> nodeList = providers.stream().map(val -> {
String tempStr = val;
try {
tempStr = URLDecoder.decode(val, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
// IP和端口
String ipPort = tempStr.substring(tempStr.indexOf("://") + 3);
ipPort = ipPort.substring(0, ipPort.indexOf("/"));
String[] ipPortArr = ipPort.split(":");
// 参数
Map<String, String> paramMap = new HashMap<>();
String params = tempStr.substring(tempStr.indexOf("?"));
String[] paramsArr = params.split("&");
for (String param : paramsArr) {
String[] split = param.split("=");
paramMap.put(split[0], split[1]);
}
DubboInfo.DubboNodeInfo dubboNodeInfo = new DubboInfo.DubboNodeInfo();
dubboNodeInfo.setIp(ipPortArr[0]);
dubboNodeInfo.setPort(NumberUtils.toInt(ipPortArr[1]));
dubboNodeInfo.setInterfaceX(paramMap.get("interface"));
dubboNodeInfo.setMethods(paramMap.get("methods").split(","));
dubboNodeInfo.setApplication(paramMap.get("application"));
return dubboNodeInfo;
}).collect(Collectors.toList());
DubboInfo dubboInfo = new DubboInfo();
dubboInfo.setInterfaceX(dubboStr);
dubboInfo.setNodeList(nodeList);
providerList.add(dubboInfo);
}
return providerList;
}
private DubboDocInfo getDefinitionByMetadata(DubboRequestParam param) {
try {
this.initMetadataClient();
String path = getNodePath(param.getService(), null, null, param.getApplication());
if (metadataClient.checkExists().forPath(path) == null) {
return null;
}
String resultType = null;
String metadata = new String(metadataClient.getData().forPath(path));
FullServiceDefinition definition = JSON.parseObject(metadata, FullServiceDefinition.class);
List<DubboDocInfo.DubboDocParam> paramList = new LinkedList<>();
for (MethodDefinition method : definition.getMethods()) {
if (Objects.equals(method.getName(), param.getMethod())) {
String[] parameterTypes = method.getParameterTypes();
resultType = method.getReturnType();
for (int i = 0; i < parameterTypes.length; i++) {
DubboDocInfo.DubboDocParam docParam = new DubboDocInfo.DubboDocParam();
docParam.setParamType(parameterTypes[i]);
docParam.setParamName("arg" + i);
paramList.add(docParam);
}
}
}
DubboDocInfo dubboDocInfo = new DubboDocInfo();
dubboDocInfo.setParams(paramList);
dubboDocInfo.setResultType(resultType);
return dubboDocInfo;
classLoadService.closeClassLoad(() -> {
File docJarFile = new File(zyplayerDocDubboLibPath + "/" + DubboDocConst.DUBBO_DOC_LIB_NAME);
file.transferTo(docJarFile);
});
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("保存文件失败:" + e.getMessage());
}
return null;
return DocResponseJson.ok();
}
private DubboDocInfo getDefinitionByJar(DubboRequestParam param) {
String resultType = null;
List<DubboDocInfo.DubboDocParam> paramList = new LinkedList<>();
try {
Class clazz = Class.forName(param.getService());
Method[] methods = clazz.getMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.equals(param.getMethod())) {
resultType = method.getGenericReturnType().getTypeName();
Type[] parameterTypes = method.getGenericParameterTypes();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameterTypes.length; i++) {
DubboDocInfo.DubboDocParam docParam = new DubboDocInfo.DubboDocParam();
docParam.setParamName(parameters[i].getName());
docParam.setParamType(parameterTypes[i].getTypeName());
paramList.add(docParam);
}
}
}
} catch (Exception e) {
return null;
}
DubboDocInfo dubboDocInfo = new DubboDocInfo();
dubboDocInfo.setParams(paramList);
dubboDocInfo.setResultType(resultType);
return dubboDocInfo;
}
String toRootDir() {
if (root.equals(Constants.PATH_SEPARATOR)) {
return root;
}
return root + Constants.PATH_SEPARATOR;
}
String getNodePath(String serviceInterface, String version, String group, String application) {
MetadataIdentifier metadataIdentifier = new MetadataIdentifier(serviceInterface, version, group, Constants.PROVIDER_SIDE, application);
return toRootDir() + metadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.PATH) + Constants.PATH_SEPARATOR + METADATA_NODE_NAME;
}
}

View File

@@ -12,6 +12,8 @@ public class DubboRequestParam {
private String method;
private String ip;
private Integer port;
private String version;
private String group;
private String paramTypes;
private String params;
@@ -70,4 +72,20 @@ public class DubboRequestParam {
public void setApplication(String application) {
this.application = application;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}

View File

@@ -24,7 +24,6 @@ public class DubboDocInfo {
private String paramDesc;
private Object paramValue;
private Integer required;
private List<DubboDocParam> params;
public String getParamName() {
return paramName;
@@ -65,14 +64,6 @@ public class DubboDocInfo {
public void setRequired(Integer required) {
this.required = required;
}
public List<DubboDocParam> getParams() {
return params;
}
public void setParams(List<DubboDocParam> params) {
this.params = params;
}
}
public Integer getVersion() {

View File

@@ -20,6 +20,8 @@ public class DubboInfo {
private String interfaceX;
private String[] methods;
private String application;
private String version;
private String group;
public Integer getPort() {
return port;
@@ -60,6 +62,22 @@ public class DubboInfo {
public void setApplication(String application) {
this.application = application;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
}
public List<DubboNodeInfo> getNodeList() {

View File

@@ -1,5 +1,6 @@
package com.zyplayer.doc.dubbo.framework.bean;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.rpc.service.GenericService;
@@ -15,24 +16,29 @@ public class ReferenceConfigHolder {
private static Map<String, ReferenceConfig> referenceConfigMap = new ConcurrentHashMap<>();
public static GenericService getBean(DubboInfo.DubboNodeInfo dubboNodeInfo) {
String name = dubboNodeInfo.getInterfaceX();
String url = "dubbo://" + dubboNodeInfo.getIp() + ":" + dubboNodeInfo.getPort() + "/" + dubboNodeInfo.getInterfaceX();
ReferenceConfig referenceConfig = referenceConfigMap.get(url);
String url = "dubbo://" + dubboNodeInfo.getIp() + ":" + dubboNodeInfo.getPort();
String referenceKey = url + "_" + StringUtils.defaultIfBlank(dubboNodeInfo.getVersion(), "0") + "_" + StringUtils.defaultIfBlank(dubboNodeInfo.getGroup(), "0");
ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);
if (referenceConfig == null) {
ApplicationConfig application = new ApplicationConfig();
application.setName("zyplayer-doc-consume");
// 参考http://dubbo.apache.org/zh-cn/docs/user/configuration/api.html
// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
referenceConfig = new ReferenceConfig<>();
// 如果点对点直连可以用reference.setUrl()指定目标地址设置url后将绕过注册中心
// 其中协议对应provider.setProtocol()的值端口对应provider.setPort()的值
// 路径对应service.setPath()的值如果未设置path缺省path为接口名
referenceConfig.setUrl(url);
referenceConfig.setInterface(name.substring(name.lastIndexOf(".") + 1));
referenceConfig.setGeneric(true);
referenceConfig.setApplication(application);
referenceConfig.setTimeout(5000);
referenceConfigMap.put(url, referenceConfig);
synchronized (ReferenceConfigHolder.class) {
ApplicationConfig application = new ApplicationConfig();
application.setName("zyplayer-doc-consume");
// 参考http://dubbo.apache.org/zh-cn/docs/user/configuration/api.html
// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
referenceConfig = new ReferenceConfig<>();
// 如果点对点直连可以用reference.setUrl()指定目标地址设置url后将绕过注册中心
// 其中协议对应provider.setProtocol()的值端口对应provider.setPort()的值,
// 路径对应service.setPath()的值如果未设置path缺省path为接口名
referenceConfig.setUrl(url);
String groupAppend = StringUtils.isNotBlank(dubboNodeInfo.getGroup()) ? dubboNodeInfo.getGroup() + "/" : "";
referenceConfig.setInterface(groupAppend + dubboNodeInfo.getInterfaceX());
referenceConfig.setGeneric(true);
referenceConfig.setApplication(application);
referenceConfig.setTimeout(5000);
referenceConfig.setVersion(dubboNodeInfo.getVersion());
referenceConfig.setGroup(dubboNodeInfo.getGroup());
referenceConfigMap.put(referenceKey, referenceConfig);
}
}
// 本项目没有dubbo里面申明的类快放弃时看源码发现可以设置generic返回一个GenericService对象通过$invoke去操作具体方法感觉又打开了一扇大门
// 本项目选择的不入侵的方式管理文档,所以文档里面就必须手动加参数,写文档那些了

View File

@@ -0,0 +1,11 @@
package com.zyplayer.doc.dubbo.framework.constant;
/**
* @author 暮光:城中城
* @since 2020年11月08日
*/
public class DubboDocConst {
/**上传的文档jar文件名*/
public static final String DUBBO_DOC_LIB_NAME = "zyplayer-doc-dubbo-libs.jar";
}

View File

@@ -1,14 +1,19 @@
package com.zyplayer.doc.dubbo.framework.service;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.annotation.DocMethod;
import com.zyplayer.doc.annotation.DocParam;
import com.zyplayer.doc.core.exception.ConfirmException;
import com.zyplayer.doc.dubbo.framework.bean.DubboResponseInfo;
import com.zyplayer.doc.dubbo.framework.bean.InterfaceType;
import com.zyplayer.doc.dubbo.framework.constant.BaseType;
import com.zyplayer.doc.dubbo.framework.constant.DubboDocConst;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.lang.reflect.*;
import java.net.JarURLConnection;
@@ -18,39 +23,111 @@ import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* 类加载服务
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
@Service
public class ClassLoadService {
private static Logger logger = LoggerFactory.getLogger(ClassLoadService.class);
@Value("${zyplayer.doc.dubbo.doc-lib-path}")
private String zyplayerDocDubboLibPath;
private URLClassLoader docClassLoader;
/**
* 获取文档jar类加载器
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
private URLClassLoader getDocClassLoader() throws Exception {
if (docClassLoader != null) {
return docClassLoader;
}
if (!FileUtil.isFile(zyplayerDocDubboLibPath + "/" + DubboDocConst.DUBBO_DOC_LIB_NAME)) {
throw new ConfirmException("请先上传文档JAR");
}
synchronized (ClassLoadService.class) {
// file:D:/maven/repository/com/zyplayer/dubbo-api/1.0/dubbo-api-1.0.jar
URL fileUrl = new URL("file:/" + zyplayerDocDubboLibPath + "/" + DubboDocConst.DUBBO_DOC_LIB_NAME);
docClassLoader = new URLClassLoader(new URL[]{fileUrl}, Thread.currentThread().getContextClassLoader());
}
return docClassLoader;
}
/**
* 关闭类加载器callback中可对文件进行覆盖上传
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public void closeClassLoad(ClassLoaderCallback callback) throws Exception {
synchronized (ClassLoadService.class) {
try {
if (docClassLoader != null) {
docClassLoader.close();
}
} catch (Exception e) {
logger.error("关闭类加载器失败", e);
}
docClassLoader = null;
if (callback != null) {
// callback方式防止刚close马上又被别人new出来了
callback.callback();
}
}
}
/**
* 加载类
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public Class<?> loadClass(String serverName) throws Exception {
try {
return this.getDocClassLoader().loadClass(serverName);
} catch (Exception e) {
// 失败之后先关闭再去加载一次
this.closeClassLoad(null);
return this.getDocClassLoader().loadClass(serverName);
}
}
// public static void main(String[] args) throws Exception {
// String serviceName = "com.zyplayer.dubbo.service.AnnotateService";
// String jarGroup = "com.zyplayer";
// String jarArtifact = "dubbo-api";
// String jarVersion = "1.0";
// String basePath = "file:D:/maven/repository";
//// String basePath = "http://nexus.dmall.com:8081/nexus/content/groups/public";
//// String basePath = "http://nexus.zyplayer.com:8081/nexus/content/groups/public";
// new ClassLoadService().loadServerMethod(serviceName, basePath, jarGroup, jarArtifact, jarVersion);
// }
// public static void main(String[] args) throws Exception {
// String serviceName = "com.zyplayer.data.service.dubbo.DataIndicatorsService";
// String jarGroup = "com.zyplayer.data";
// String jarArtifact = "data-api-client";
// String jarVersion = "1.0.9.SNAPSHOTS";
// String basePath = "http://nexus.zyplayer.com:8081/nexus/content/groups/public";
// new ClassLoadService().loadServerMethod(serviceName, basePath, jarGroup, jarArtifact, jarVersion);
// }
public static void main(String[] args) throws Exception {
String serviceName = "com.dmall.data.service.dubbo.DataIndicatorsService";
String jarGroup = "com.dmall.data";
String jarArtifact = "data-api-client";
String jarVersion = "1.0.9.SNAPSHOTS";
String basePath = "http://nexus.dmall.com:8081/nexus/content/groups/public";
new ClassLoadService().loadServerMethod(serviceName, basePath, jarGroup, jarArtifact, jarVersion);
}
public void loadServerMethod(String serverName, String basePath, String jarGroup, String jarArtifact, String jarVersion) throws Exception {
public void loadServerMethod(String serverName) throws Exception {
// jar:file:D:/maven/repository/com/zyplayer/dubbo-api/1.0/dubbo-api-1.0.jar!/
String jarPath = jarGroup.replaceAll("\\.", "/") + "/" + jarArtifact + "/" + jarVersion + "/" + jarArtifact + "-" + jarVersion + ".jar";
URL jarUrl = new URL("jar:" + basePath + "/" + jarPath + "!/");
String docJarFileUrl = "file:/" + zyplayerDocDubboLibPath + "/" + DubboDocConst.DUBBO_DOC_LIB_NAME;
URL jarUrl = new URL("jar:" + docJarFileUrl + "!/");
JarFile jar = ((JarURLConnection) jarUrl.openConnection()).getJarFile();
JarEntry jarEntry = jar.getJarEntry(serverName.replaceAll("\\.", "/") + ".class");
if (jarEntry == null) {
logger.info("未找到类");
return;
}
URL fileUrl = new URL(basePath + "/" + jarPath);
URL fileUrl = new URL(docJarFileUrl);
URLClassLoader classLoader = new URLClassLoader(new URL[]{fileUrl}, Thread.currentThread().getContextClassLoader());
Class<?> clazz = classLoader.loadClass(serverName);
Method[] methods = clazz.getMethods();
@@ -220,8 +297,8 @@ public class ClassLoadService {
List<DubboResponseInfo> paramList = new LinkedList<>();
Field[] fieldArr = clazz.getDeclaredFields();
for (Field field : fieldArr) {
field.setAccessible(true);
try {
field.setAccessible(true);
paramList.add(this.getInfoByField(classLoader, field, recursion));
} catch (Exception e) {
e.printStackTrace();

View File

@@ -0,0 +1,18 @@
package com.zyplayer.doc.dubbo.framework.service;
/**
*
*
* @author 暮光:城中城
* @since 2018年8月19日
*/
public interface ClassLoaderCallback {
/**
* 回调
*
* @author 暮光:城中城
* @since 2020年10月08日
*/
void callback() throws Exception;
}

View File

@@ -0,0 +1,79 @@
package com.zyplayer.doc.dubbo.framework.service;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.dubbo.controller.vo.NacosServiceInfoVo;
import com.zyplayer.doc.dubbo.controller.vo.NacosServiceListVo;
import com.zyplayer.doc.dubbo.framework.bean.DubboInfo;
import com.zyplayer.doc.dubbo.framework.bean.NacosDubboInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
import java.util.List;
/**
* nacos方式加载文档服务
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
@Service
public class NacosDocService {
@Value("${zyplayer.doc.dubbo.nacos.url:}")
private String nacosUrl;
// @Value("${zyplayer.doc.dubbo.nacos.service:}")
// private String nacosService;
/**
* 是否开启nacos文档
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public boolean isEnable() {
return StringUtils.isNotBlank(nacosUrl);
}
/**
* 通过nacos方式获取所有服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
public List<DubboInfo> getDubboInfoByNacos() {
List<DubboInfo> providerList = new LinkedList<>();
// 获取所有的服务列表
String serviceListStr = HttpUtil.get(nacosUrl + "/v1/ns/catalog/services?withInstances=false&pageNo=1&pageSize=100000");
NacosServiceInfoVo nacosServiceInfoVo = JSON.parseObject(serviceListStr, NacosServiceInfoVo.class);
if (nacosServiceInfoVo == null || nacosServiceInfoVo.getServiceList().isEmpty()) {
return providerList;
}
for (NacosServiceListVo service : nacosServiceInfoVo.getServiceList()) {
String serviceName = service.getName();
String resultStr = HttpUtil.get(nacosUrl + "/v1/ns/instance/list?serviceName=" + serviceName);
NacosDubboInfo dubboInstance = JSON.parseObject(resultStr, NacosDubboInfo.class);
List<NacosDubboInfo.HostsBean> hosts = dubboInstance.getHosts();
DubboInfo dubboInfo = new DubboInfo();
List<DubboInfo.DubboNodeInfo> nodeList = new LinkedList<>();
for (NacosDubboInfo.HostsBean host : hosts) {
DubboInfo.DubboNodeInfo dubboNodeInfo = new DubboInfo.DubboNodeInfo();
dubboNodeInfo.setIp(host.getIp());
dubboNodeInfo.setPort(host.getPort());
dubboNodeInfo.setInterfaceX(host.getMetadata().getInterfaceX());
dubboNodeInfo.setMethods(host.getMetadata().getMethods().split(","));
dubboNodeInfo.setApplication(host.getMetadata().getApplication());
nodeList.add(dubboNodeInfo);
}
if (serviceName.contains(":")) {
serviceName = serviceName.substring(serviceName.indexOf(":") + 1);
}
dubboInfo.setInterfaceX(serviceName);
dubboInfo.setNodeList(nodeList);
providerList.add(dubboInfo);
}
return providerList;
}
}

View File

@@ -0,0 +1,242 @@
package com.zyplayer.doc.dubbo.framework.service;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.dubbo.controller.param.DubboRequestParam;
import com.zyplayer.doc.dubbo.framework.bean.DubboDocInfo;
import com.zyplayer.doc.dubbo.framework.bean.DubboInfo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
import org.apache.dubbo.metadata.definition.model.MethodDefinition;
import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;
/**
* zookeeper方式加载文档服务
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
@Service
public class ZookeeperDocService {
@Value("${zyplayer.doc.dubbo.zookeeper.url:}")
private String serviceZookeeperUrl;
@Value("${zyplayer.doc.dubbo.zookeeper.metadata-url:}")
private String metadataZookeeperUrl;
@Resource
ClassLoadService classLoadService;
private CuratorFramework serverClient;
private CuratorFramework metadataClient;
private final static String DEFAULT_ROOT = "dubbo";
private final static String METADATA_NODE_NAME = "service.data";
private String root;
/**
* zookeeper初始化
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
@PostConstruct
private void init() {
// 初始化zk注册中心连接
if (StringUtils.isNotBlank(serviceZookeeperUrl)) {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
serverClient = CuratorFrameworkFactory.newClient(serviceZookeeperUrl, retryPolicy);
serverClient.start();
}
// 初始化zk注册中心元数据信息
if (StringUtils.isNotBlank(metadataZookeeperUrl)) {
URL url = UrlUtils.parseURL(metadataZookeeperUrl, Collections.emptyMap());
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(Constants.PATH_SEPARATOR)) {
group = Constants.PATH_SEPARATOR + group;
}
this.root = group;
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
metadataClient = CuratorFrameworkFactory.newClient(metadataZookeeperUrl, retryPolicy);
metadataClient.start();
}
}
/**
* 是否启用了zk文档
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public boolean isEnable() {
return StringUtils.isNotBlank(serviceZookeeperUrl);
}
/**
* 通过Zookeeper方式获取所有服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
public List<DubboInfo> getDubboInfoByZookeeper() throws Exception {
if (serverClient == null) {
return null;
}
List<String> dubboList = serverClient.getChildren().forPath("/dubbo");
if (dubboList == null || dubboList.isEmpty()) {
return Collections.emptyList();
}
List<DubboInfo> providerList = new LinkedList<>();
for (String dubboStr : dubboList) {
String path = "/dubbo/" + dubboStr + "/providers";
if (serverClient.checkExists().forPath(path) == null) {
continue;
}
List<String> providers = serverClient.getChildren().forPath(path);
List<DubboInfo.DubboNodeInfo> nodeList = providers.stream().map(val -> {
String tempStr = val;
try {
tempStr = URLDecoder.decode(val, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
// IP和端口
String ipPort = tempStr.substring(tempStr.indexOf("://") + 3);
ipPort = ipPort.substring(0, ipPort.indexOf("/"));
String[] ipPortArr = ipPort.split(":");
// 参数
Map<String, String> paramMap = new HashMap<>();
String params = tempStr.substring(tempStr.indexOf("?") + 1);
String[] paramsArr = params.split("&");
for (String param : paramsArr) {
String[] split = param.split("=");
paramMap.put(split[0], split[1]);
}
DubboInfo.DubboNodeInfo dubboNodeInfo = new DubboInfo.DubboNodeInfo();
dubboNodeInfo.setIp(ipPortArr[0]);
dubboNodeInfo.setPort(NumberUtils.toInt(ipPortArr[1]));
dubboNodeInfo.setInterfaceX(paramMap.get("interface"));
dubboNodeInfo.setMethods(paramMap.get("methods").split(","));
dubboNodeInfo.setApplication(paramMap.get("application"));
dubboNodeInfo.setVersion(paramMap.get("version"));
dubboNodeInfo.setGroup(paramMap.get("group"));
return dubboNodeInfo;
}).collect(Collectors.toList());
DubboInfo dubboInfo = new DubboInfo();
dubboInfo.setInterfaceX(dubboStr);
dubboInfo.setNodeList(nodeList);
providerList.add(dubboInfo);
}
return providerList;
}
/**
* 通过zk中的meta信息获取文档
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public DubboDocInfo getDefinitionByMetadata(DubboRequestParam param) {
if (metadataClient == null) {
return null;
}
try {
String path = getNodePath(param.getService(), null, null, param.getApplication());
if (metadataClient.checkExists().forPath(path) == null) {
return null;
}
String resultType = null;
String metadata = new String(metadataClient.getData().forPath(path));
FullServiceDefinition definition = JSON.parseObject(metadata, FullServiceDefinition.class);
List<DubboDocInfo.DubboDocParam> paramList = new LinkedList<>();
for (MethodDefinition method : definition.getMethods()) {
if (Objects.equals(method.getName(), param.getMethod())) {
String[] parameterTypes = method.getParameterTypes();
resultType = method.getReturnType();
for (int i = 0; i < parameterTypes.length; i++) {
DubboDocInfo.DubboDocParam docParam = new DubboDocInfo.DubboDocParam();
docParam.setParamType(parameterTypes[i]);
docParam.setParamName("arg" + i);
paramList.add(docParam);
}
}
}
DubboDocInfo dubboDocInfo = new DubboDocInfo();
dubboDocInfo.setParams(paramList);
dubboDocInfo.setResultType(resultType);
return dubboDocInfo;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 通过jar方式获取文档
*
* @author 暮光:城中城
* @since 2020年11月08日
*/
public DubboDocInfo getDefinitionByJar(DubboRequestParam param) {
String resultType = null;
List<DubboDocInfo.DubboDocParam> paramList = new LinkedList<>();
try {
Class clazz = classLoadService.loadClass(param.getService());
Method[] methods = clazz.getMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.equals(param.getMethod())) {
resultType = method.getGenericReturnType().getTypeName();
Type[] parameterTypes = method.getGenericParameterTypes();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameterTypes.length; i++) {
DubboDocInfo.DubboDocParam docParam = new DubboDocInfo.DubboDocParam();
docParam.setParamName(parameters[i].getName());
docParam.setParamType(parameterTypes[i].getTypeName());
paramList.add(docParam);
}
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
DubboDocInfo dubboDocInfo = new DubboDocInfo();
dubboDocInfo.setParams(paramList);
dubboDocInfo.setResultType(resultType);
return dubboDocInfo;
}
private String toRootDir() {
if (Objects.isNull(root)) {
return Constants.PATH_SEPARATOR;
}
if (Objects.equals(Constants.PATH_SEPARATOR, root)) {
return root;
}
return root + Constants.PATH_SEPARATOR;
}
private String getNodePath(String serviceInterface, String version, String group, String application) {
MetadataIdentifier metadataIdentifier = new MetadataIdentifier(serviceInterface, version, group, Constants.PROVIDER_SIDE, application);
return toRootDir() + metadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.PATH) + Constants.PATH_SEPARATOR + METADATA_NODE_NAME;
}
}

View File

@@ -0,0 +1 @@
.header-right-user-name{color:#fff;padding-right:5px}.el-menu-vertical{border-right:0}.el-menu-vertical,.el-menu-vertical .el-menu{background:#fafafa}.el-header{background-color:#409eff;color:#333;line-height:40px;text-align:right;height:40px!important}body,html{margin:0;padding:0}#app,.el-container,.el-menu,body,html{height:100%}.el-menu{-webkit-box-sizing:border-box;box-sizing:border-box;border-right:0}.el-menu,.el-tree{margin-right:3px}.el-tree-node__content{padding-right:20px}.el-header{background-color:#1d4e89!important}.el-button-group>.el-button:first-child{padding:0!important;border:0}.login-container{border-radius:5px;-moz-border-radius:5px;background-clip:padding-box;margin:0 auto;width:350px;padding:35px 35px 15px 35px;background:#fff;border:1px solid #eaeaea;-webkit-box-shadow:0 0 25px #cac6c6;box-shadow:0 0 25px #cac6c6}.title{margin:0 auto 40px auto;text-align:center;color:#505458}.remember{margin:0 0 35px 0}.my-info-vue .box-card{margin:10px}.dubbo-doc-view{padding:0 10px}.dubbo-doc-view .el-tabs--border-card>.el-tabs__content{height:calc(100vh - 180px);overflow-y:auto}.dubbo-doc-view .request-result pre{margin:0}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,513 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<!--无论发布在哪、如何修改源码,请勿删除本行原作者信息,感谢-->
<meta name="author" content="开发者列表暮光城中城项目地址https://gitee.com/zyplayer/zyplayer-doc" />
<title>dubbo文档管理系统</title>
<link rel="shortcut icon" href="webjars/doc-dubbo/img/dubbo.ico"/>
<link rel="stylesheet" href="webjars/doc-dubbo/css/element-ui.css">
<link rel="stylesheet" href="webjars/doc-dubbo/css/doc-dubbo.css" />
</head>
<body>
<div id="app">
<el-container style="height: 100%;">
<el-aside width="auto" style="height: 100%;">
<div class="logo" @click="aboutDialogVisible = true">zyplayer-doc-dubbo</div>
<div style="padding: 10px;">
<div align="center">
<el-dropdown split-button type="primary" @command="dropdownCommand">
<el-upload class="upload-page-file" action="zyplayer-doc-dubbo/doc-dubbo/uploadDocJar"
:on-success="uploadFileSuccess" :on-error="uploadFileError"
name="file" :show-file-list="false" :limit="999">
<el-button type="primary" icon="el-icon-upload">上传文档JAR</el-button>
</el-upload>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="reload" icon="el-icon-refresh">重新加载服务列表</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<!--<el-row><el-switch v-model="isCollapse"></el-switch></el-row>-->
<el-input v-model="searchKeywords" placeholder="搜索文档" style="margin: 10px 0;">
<el-button slot="append" icon="el-icon-search" v-on:click="searchByKeywords"></el-button>
</el-input>
<!--<el-menu default-active="" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">-->
<!--<el-submenu index="1">-->
<!--<template slot="title">-->
<!--<i class="el-icon-setting"></i>-->
<!--<span slot="title">文档管理</span>-->
<!--</template>-->
<!--<el-menu-item index="1-1">管理服务列表</el-menu-item>-->
<!--</el-submenu>-->
<!--</el-menu>-->
<el-tree :data="pathIndex" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
</el-aside>
<el-container>
<el-tabs type="border-card" style="width: 100%;">
<el-tab-pane label="接口说明">
<div v-if="!dubboInfo.interface">
请先选择服务
</div>
<el-form v-else label-width="80px">
<el-form-item label="服务:">
{{dubboInfo.interface}}
</el-form-item>
<el-form-item label="方法:">
{{dubboInfo.method}}
</el-form-item>
<el-form-item label="说明:">
<div v-if="dubboInfoExplainShow">
<pre>{{dubboInfo.docInfo.explain}}<el-button @click.prevent="dubboInfoExplainShow = false;" style="float: right;">编辑</el-button></pre>
</div>
<div v-else>
<el-input type="textarea" :rows="4" placeholder="维护人员、使用说明、便于搜索的信息" v-model="docInfoExplainInput"></el-input>
<el-button @click.prevent="dubboInfoExplainShow = true;" style="float: right;margin: 5px;">取消</el-button>
<el-button type="primary" @click.prevent="saveDocInfoExplain" style="float: right;margin: 5px;">保存</el-button>
</div>
</el-form-item>
<el-form-item label="节点:">
<el-table :data="dubboInfo.nodeList" border style="width: 100%">
<el-table-column prop="application" label="应用"></el-table-column>
<el-table-column prop="ip" label="IP"></el-table-column>
<el-table-column prop="port" label="端口"></el-table-column>
</el-table>
</el-form-item>
<el-form-item label="参数:">
<!--<div slot="label">-->
<!--<el-tooltip placement="top">-->
<!--<div slot="content">1. 顺序必须和参数的顺序一致<br/>2. 参数名意义不大,可不填</div>-->
<!--<i class="el-icon-info" style="color: #aaa;"></i>-->
<!--</el-tooltip>-->
<!--参数:-->
<!--</div>-->
<el-table :data="docParamList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="顺序" width="100">
<template slot-scope="scope">{{scope.$index}}</template>
</el-table-column>
<el-table-column label="参数名" width="200">
<template slot-scope="scope">
<el-input v-model="scope.row.paramName"></el-input>
</template>
</el-table-column>
<el-table-column label="类型" width="300">
<template slot-scope="scope">{{scope.row.paramType}}</template>
<!--<template slot-scope="scope">-->
<!--<el-select v-model="scope.row.paramType" filterable allow-create clearable placeholder="请选择" style="width: 100%;">-->
<!--<el-option v-for="item in paramTypeOptions" :key="item.value" :label="item.value" :value="item.value"></el-option>-->
<!--</el-select>-->
<!--</template>-->
</el-table-column>
<el-table-column label="说明">
<template slot-scope="scope">
<el-input v-model="scope.row.paramDesc"></el-input>
</template>
</el-table-column>
</el-table>
<el-button @click.prevent="saveDocInfoParam" type="primary" style="float: right;margin: 5px;">保存</el-button>
<!--<el-button @click.prevent="addDocParam" style="float: right;margin: 5px;">添加</el-button>-->
</el-form-item>
<el-form-item label="返回值:">
{{dubboInfo.docInfo.resultType}}
</el-form-item>
<el-form-item label="结果:">
<div v-if="dubboInfoResultShow">
<pre>{{dubboInfo.docInfo.result}}<el-button @click.prevent="dubboInfoResultShow = false;" style="float: right;">编辑</el-button></pre>
</div>
<div v-else>
<el-input type="textarea" :rows="4" placeholder="结果集说明等" v-model="docInfoResultInput"></el-input>
<el-button @click.prevent="dubboInfoResultShow = true;" style="float: right;margin: 5px;">取消</el-button>
<el-button type="primary" @click.prevent="saveDocInfoResult" style="float: right;margin: 5px;">保存</el-button>
</div>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="在线调试">
<div v-if="!dubboInfo.interface">
请先选择服务
</div>
<div v-loading="onlineDebugLoading" v-else>
<el-input placeholder="请输入内容" v-model="dubboInfo.function" class="input-with-select">
<el-select v-model="requestHostValue" slot="prepend" placeholder="请选择" style="width: 200px;">
<el-option v-for="item in requestHostOptions" :key="item.value" :label="item.value" :value="item.value"></el-option>
</el-select>
<el-button slot="append" @click.prevent="requestExecute">执行</el-button>
</el-input>
<el-form label-width="100px" label-position="top">
<el-form-item label="请求参数:">
<el-table :data="docParamRequestList" border style="width: 100%; margin: 10px 0;">
<el-table-column label="顺序" width="100">
<template slot-scope="scope">{{scope.$index}}</template>
</el-table-column>
<el-table-column label="参数名">
<template slot-scope="scope">{{scope.row.paramName}}</template>
</el-table-column>
<el-table-column label="类型">
<template slot-scope="scope">{{scope.row.paramType}}</template>
</el-table-column>
<el-table-column label="参数值">
<template slot-scope="scope">
<el-input v-model="scope.row.paramValue"></el-input>
</template>
</el-table-column>
<el-table-column label="说明">
<template slot-scope="scope">{{scope.row.paramDesc}}</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="请求结果:">
<div v-html="requestResult"></div>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</el-container>
</el-container>
<el-dialog title="关于zyplayer-doc-dubbo" :visible.sync="aboutDialogVisible" width="600px">
<el-form>
<el-form-item label="项目地址:">
<a target="_blank" href="https://gitee.com/zyplayer/zyplayer-doc">zyplayer-doc</a>
</el-form-item>
<el-form-item label="开发人员:">
<a target="_blank" href="http://zyplayer.com">暮光:城中城</a>
</el-form-item>
<template v-if="upgradeInfo.lastVersion">
<el-form-item label="当前版本:">{{upgradeInfo.nowVersion}}</el-form-item>
<el-form-item label="最新版本:">{{upgradeInfo.lastVersion}}</el-form-item>
<el-form-item label="升级地址:">
<a target="_blank" :href="upgradeInfo.upgradeUrl">{{upgradeInfo.upgradeUrl}}</a>
</el-form-item>
<el-form-item label="升级内容:">{{upgradeInfo.upgradeContent}}</el-form-item>
</template>
<el-form-item label="">
欢迎加群讨论QQ群号466363173欢迎提交需求欢迎使用和加入开发
</el-form-item>
</el-form>
</el-dialog>
</div>
</body>
<script type="text/javascript" src="webjars/doc-dubbo/vue/vue.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/element-ui.js"></script>
<!-- ajax 用到了jquery -->
<script type="text/javascript" src="webjars/doc-dubbo/js/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/common.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/toast.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/formatjson.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/doc-dubbo-tree.js"></script>
<script>
var app = new Vue({
el: '#app',
data() {
return {
isCollapse: false,
aboutDialogVisible: false,
onlineDebugLoading: false,
pathIndex: [],
defaultProps: {
children: 'children',
label: 'label'
},
// 展示的信息
dubboInfo: {},
dubboInfoExplainShow: true,
docInfoExplainInput: "",
dubboInfoResultShow: true,
docInfoResultInput: "",
// 请求的IP端口下拉选项
requestHostOptions: [],
requestHostValue: "",
requestResult: "",
// 依据目录树存储的map全局对象
treePathDataMap: new Map(),
// dubbo列表
dubboDocList: [],
dubboDocMap: [],
// 搜索的输入内容
searchKeywords: "",
docParamList: [],
docParamRequestList: [],
// 参数类型选项
paramTypeOptions: [{
value: 'java.lang.String'
}, {
value: 'java.lang.Long'
}, {
value: 'java.lang.Integer'
}],
paramTypeValue: "java.lang.String",
// 升级信息
upgradeInfo: {},
}
},
watch: {
},
mounted: function () {
// 无论发布在哪、如何修改源码,请勿删除本行原作者信息,感谢
console.log("%c项目信息\n开发者列表暮光城中城\n项目地址https://gitee.com/zyplayer/zyplayer-doc", "color:red");
this.doGetServiceList();
this.checkSystemUpgrade();
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
handleNodeClick(data) {
if (data.children == null) {
console.log(data);
var path = data.interface;
var application = data.application;
var docInfo = app.dubboDocMap[path];
if (!!docInfo) {
this.createDocInfo(path, data.method);
} else {
var service = path.substring(0, path.lastIndexOf("."));
var method = path.substring(path.lastIndexOf(".") + 1, path.length);
var param = {service: service, method: method, application: application};
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/findDocInfo", "post", "json", param, function (json) {
if (validateResult(json)) {
if (!!json.data) {
app.dubboDocMap[json.data.function] = json.data;
}
app.createDocInfo(path, method);
}
});
}
//console.log(app.dubboInfo);
}
},
createDocInfo(path, method) {
var docInfo = app.dubboDocMap[path];
var dubboInfo = app.treePathDataMap.get(path);
dubboInfo.method = method;
dubboInfo.function = path;
dubboInfo.docInfo = docInfo || {};
// 清空再赋值才会重新渲染
app.dubboInfo = {};
app.dubboInfo = dubboInfo;
app.docInfoExplainInput = dubboInfo.docInfo.explain;
app.docParamList = [];
app.docParamList = dubboInfo.docInfo.params || [];
this.createDocParamRequestList();
// 请求相关
app.requestResult = "";
app.requestHostValue = "";
app.requestHostOptions = [];
for (var i = 0; i < dubboInfo.nodeList.length; i++) {
var item = dubboInfo.nodeList[i];
let option = item.ip + ":" + item.port;
if (!!item.version) option += " V" + item.version;
if (!!item.group) option += " G" + item.group;
app.requestHostOptions.push({value: option});
}
if (app.requestHostOptions.length > 0) {
app.requestHostValue = app.requestHostOptions[0].value;
}
},
uploadFileError(err) {
app.$message({message: "上传失败," + err, type: 'error'});
},
uploadFileSuccess(response) {
if (validateResult(response)) {
app.$message({message: "上传成功!", type: 'success'});
}
},
reloadService() {
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/reloadService", "post", "json", {}, function (json) {
if (validateResult(json)) {
app.$message({message: '加载成功!', type: 'success'});
app.doGetServiceList();
}
});
},
dropdownCommand(command) {
if(command == 'reload') {
this.reloadService();
}
},
searchByKeywords() {
app.pathIndex = createTreeViewByTreeWithMerge(app.dubboDocList, app.searchKeywords);
},
doGetServiceList() {
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/getDocList", "post", "json", {}, function (json) {
if (validateResult(json)) {
app.dubboDocList = json.data.serverList || [];
app.dubboDocMap = json.data.docMap || {};
app.pathIndex = createTreeViewByTreeWithMerge(app.dubboDocList);
}
});
},
saveDocInfoExplain(){
this.doSaveDocInfo(app.docInfoExplainInput, null, null, true);
},
saveDocInfoResult(){
this.doSaveDocInfo(null, null, app.docInfoResultInput, true);
},
saveDocInfoParam() {
var docParamList = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
if (isNotEmpty(item.paramType)) {
docParamList.push(item);
}
}
var paramsJson = JSON.stringify(docParamList);
this.doSaveDocInfo(null, paramsJson, null, true);
},
createDocParamRequestList() {
var docParamList = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
if (isNotEmpty(item.paramType) || isNotEmpty(item.paramDesc)) {
docParamList.push(item);
}
}
app.docParamRequestList = docParamList;
},
doSaveDocInfo(explain, params, result, showSuccess){
var param = {
service: app.dubboInfo.interface,
method: app.dubboInfo.method,
resultType: app.dubboInfo.resultType,
paramValue: app.dubboInfo.paramValue,
version: app.dubboInfo.docInfo.version || 0,
explain: explain,
result: result,
paramsJson: params,
};
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/saveDoc", "post", "json", param, function (json) {
if (validateResult(json)) {
app.dubboDocMap[json.data.function] = json.data;
app.dubboInfo.docInfo = json.data;
app.dubboInfoExplainShow = true;
app.dubboInfoResultShow = true;
app.docParamList = json.data.params || [];
app.createDocParamRequestList();
if (showSuccess) {
Toast.success("保存成功!");
}
}
});
},
addDocParam() {
var leadAdd = app.docParamList.length <= 0;
if (!leadAdd) {
var last = app.docParamList[app.docParamList.length - 1];
if (isNotEmpty(last.paramType) || isNotEmpty(last.paramDesc)) {
leadAdd = true;
}
}
if (leadAdd) {
app.docParamList.push({
paramName: '',
paramType: '',
paramDesc: '',
paramValue: '',
});
}
},
requestExecute() {
var fuc = app.dubboInfo.function;
var hostValue = app.requestHostValue;
var service = fuc.substring(0, fuc.lastIndexOf("."));
var method = fuc.substring(fuc.lastIndexOf(".") + 1, fuc.length);
var paramArr = hostValue.split(" ");
var ipPortArr = paramArr[0].split(":");
var version = '', group = '';
paramArr.forEach(item => {
if (item.startsWith("V")) version = item.substring(1, item.length);
if (item.startsWith("G")) group = item.substring(1, item.length);
});
var paramTypes = [];
var params = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
paramTypes.push(item.paramType);
params.push(item.paramValue || '');
}
var param = {
service: service,
method: method,
ip: ipPortArr[0],
port: ipPortArr[1],
version: version,
group: group,
paramTypes: JSON.stringify(paramTypes),
params: JSON.stringify(params),
};
app.requestResult = "";
app.onlineDebugLoading = true;
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/request", "post", "json", param, function (json) {
app.onlineDebugLoading = false;
if (json.errCode == 200) {
try {
app.requestResult = Formatjson.processObjectToHtmlPre(JSON.parse(json.data), 0, false, false, false, false);
} catch (e) {
try {
app.requestResult = Formatjson.processObjectToHtmlPre(json.data, 0, false, false, false, false);
} catch (e) {
app.requestResult = json.data;
}
}
var paramsJson = JSON.stringify(app.docParamRequestList);
app.doSaveDocInfo(null, paramsJson, null, false);
} else {
app.requestResult = json.errMsg;
}
}, function (err) {
app.onlineDebugLoading = false;
app.requestResult = err.responseJSON.message;
});
},
checkSystemUpgrade() {
ajaxTemp("system/info/upgrade", "post", "json", {}, function (json) {
if (json.errCode == 200 && !!json.data) {
app.upgradeInfo = json.data;
console.log("zyplayer-doc发现新版本"
+ "\n升级地址" + json.data.upgradeUrl
+ "\n当前版本" + json.data.nowVersion
+ "\n最新版本" + json.data.lastVersion
+ "\n升级内容" + json.data.upgradeContent
);
}
});
},
}
});
</script>
<style>
html,body,#app {
margin: 0;
padding: 0;
height: 100%;
}
pre{margin: 0;}
.el-menu {
box-sizing: border-box;
border-right: 0;
margin-right: 3px;
}
.el-tree{
margin-right: 3px;
}
.el-tree-node__content{
padding-right: 20px;
}
.el-tabs--border-card>.el-tabs__content{
height: calc(100vh - 100px);overflow-y: auto;
}
.logo{
background: linear-gradient(-90deg, #03DDE4 0%, #30AFED 51%, #8755FF 100%); cursor: pointer;
width: 100%; height:60px;line-height:60px;font-size: 25px;color: #fff;text-align: center;
}
.el-button-group>.el-button:first-child{padding: 0!important;border: 0;}
</style>
</html>

View File

@@ -1,482 +1 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<!--无论发布在哪、如何修改源码,请勿删除本行原作者信息,感谢-->
<meta name="author" content="开发者列表暮光城中城项目地址https://gitee.com/zyplayer/zyplayer-doc" />
<title>dubbo文档管理系统</title>
<link rel="shortcut icon" href="webjars/doc-dubbo/img/dubbo.ico"/>
<link rel="stylesheet" href="webjars/doc-dubbo/css/element-ui.css">
<link rel="stylesheet" href="webjars/doc-dubbo/css/doc-dubbo.css" />
</head>
<body>
<div id="app">
<el-container style="height: 100%;">
<el-aside width="auto" style="height: 100%;">
<div class="logo" @click="aboutDialogVisible = true">zyplayer-doc-dubbo</div>
<div style="padding: 10px;">
<div align="center"><el-button type="primary" v-on:click="reloadService" icon="el-icon-refresh" style="width: 100%;">重新加载服务列表</el-button></div>
<!--<el-row><el-switch v-model="isCollapse"></el-switch></el-row>-->
<el-input v-model="searchKeywords" placeholder="搜索文档" style="margin: 10px 0;">
<el-button slot="append" icon="el-icon-search" v-on:click="searchByKeywords"></el-button>
</el-input>
<!--<el-menu default-active="" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">-->
<!--<el-submenu index="1">-->
<!--<template slot="title">-->
<!--<i class="el-icon-setting"></i>-->
<!--<span slot="title">文档管理</span>-->
<!--</template>-->
<!--<el-menu-item index="1-1">管理服务列表</el-menu-item>-->
<!--</el-submenu>-->
<!--</el-menu>-->
<el-tree :data="pathIndex" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
</el-aside>
<el-container>
<el-tabs type="border-card" style="width: 100%;">
<el-tab-pane label="接口说明">
<div v-if="!dubboInfo.interface">
请先选择服务
</div>
<el-form v-else label-width="80px">
<el-form-item label="服务:">
{{dubboInfo.interface}}
</el-form-item>
<el-form-item label="方法:">
{{dubboInfo.method}}
</el-form-item>
<el-form-item label="说明:">
<div v-if="dubboInfoExplainShow">
<pre>{{dubboInfo.docInfo.explain}}<el-button @click.prevent="dubboInfoExplainShow = false;" style="float: right;">编辑</el-button></pre>
</div>
<div v-else>
<el-input type="textarea" :rows="4" placeholder="维护人员、使用说明、便于搜索的信息" v-model="docInfoExplainInput"></el-input>
<el-button @click.prevent="dubboInfoExplainShow = true;" style="float: right;margin: 5px;">取消</el-button>
<el-button type="primary" @click.prevent="saveDocInfoExplain" style="float: right;margin: 5px;">保存</el-button>
</div>
</el-form-item>
<el-form-item label="节点:">
<el-table :data="dubboInfo.nodeList" border style="width: 100%">
<el-table-column prop="application" label="应用"></el-table-column>
<el-table-column prop="ip" label="IP"></el-table-column>
<el-table-column prop="port" label="端口"></el-table-column>
</el-table>
</el-form-item>
<el-form-item label="参数:">
<!--<div slot="label">-->
<!--<el-tooltip placement="top">-->
<!--<div slot="content">1. 顺序必须和参数的顺序一致<br/>2. 参数名意义不大,可不填</div>-->
<!--<i class="el-icon-info" style="color: #aaa;"></i>-->
<!--</el-tooltip>-->
<!--参数:-->
<!--</div>-->
<el-table :data="docParamList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="顺序" width="100">
<template slot-scope="scope">{{scope.$index}}</template>
</el-table-column>
<el-table-column label="参数名" width="200">
<template slot-scope="scope">
<el-input v-model="scope.row.paramName"></el-input>
</template>
</el-table-column>
<el-table-column label="类型" width="300">
<template slot-scope="scope">{{scope.row.paramType}}</template>
<!--<template slot-scope="scope">-->
<!--<el-select v-model="scope.row.paramType" filterable allow-create clearable placeholder="请选择" style="width: 100%;">-->
<!--<el-option v-for="item in paramTypeOptions" :key="item.value" :label="item.value" :value="item.value"></el-option>-->
<!--</el-select>-->
<!--</template>-->
</el-table-column>
<el-table-column label="说明">
<template slot-scope="scope">
<el-input v-model="scope.row.paramDesc"></el-input>
</template>
</el-table-column>
</el-table>
<el-button @click.prevent="saveDocInfoParam" type="primary" style="float: right;margin: 5px;">保存</el-button>
<!--<el-button @click.prevent="addDocParam" style="float: right;margin: 5px;">添加</el-button>-->
</el-form-item>
<el-form-item label="返回值:">
{{dubboInfo.docInfo.resultType}}
</el-form-item>
<el-form-item label="结果:">
<div v-if="dubboInfoResultShow">
<pre>{{dubboInfo.docInfo.result}}<el-button @click.prevent="dubboInfoResultShow = false;" style="float: right;">编辑</el-button></pre>
</div>
<div v-else>
<el-input type="textarea" :rows="4" placeholder="结果集说明等" v-model="docInfoResultInput"></el-input>
<el-button @click.prevent="dubboInfoResultShow = true;" style="float: right;margin: 5px;">取消</el-button>
<el-button type="primary" @click.prevent="saveDocInfoResult" style="float: right;margin: 5px;">保存</el-button>
</div>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="在线调试">
<div v-if="!dubboInfo.interface">
请先选择服务
</div>
<div v-loading="onlineDebugLoading" v-else>
<el-input placeholder="请输入内容" v-model="dubboInfo.function" class="input-with-select">
<el-select v-model="requestHostValue" slot="prepend" placeholder="请选择" style="width: 200px;">
<el-option v-for="item in requestHostOptions" :key="item.value" :label="item.value" :value="item.value"></el-option>
</el-select>
<el-button slot="append" @click.prevent="requestExecute">执行</el-button>
</el-input>
<el-form label-width="100px" label-position="top">
<el-form-item label="请求参数:">
<el-table :data="docParamRequestList" border style="width: 100%; margin: 10px 0;">
<el-table-column label="顺序" width="100">
<template slot-scope="scope">{{scope.$index}}</template>
</el-table-column>
<el-table-column label="参数名">
<template slot-scope="scope">{{scope.row.paramName}}</template>
</el-table-column>
<el-table-column label="类型">
<template slot-scope="scope">{{scope.row.paramType}}</template>
</el-table-column>
<el-table-column label="参数值">
<template slot-scope="scope">
<el-input v-model="scope.row.paramValue"></el-input>
</template>
</el-table-column>
<el-table-column label="说明">
<template slot-scope="scope">{{scope.row.paramDesc}}</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="请求结果:">
<div v-html="requestResult"></div>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</el-container>
</el-container>
<el-dialog title="关于zyplayer-doc-dubbo" :visible.sync="aboutDialogVisible" width="600px">
<el-form>
<el-form-item label="项目地址:">
<a target="_blank" href="https://gitee.com/zyplayer/zyplayer-doc">zyplayer-doc</a>
</el-form-item>
<el-form-item label="开发人员:">
<a target="_blank" href="http://zyplayer.com">暮光:城中城</a>
</el-form-item>
<template v-if="upgradeInfo.lastVersion">
<el-form-item label="当前版本:">{{upgradeInfo.nowVersion}}</el-form-item>
<el-form-item label="最新版本:">{{upgradeInfo.lastVersion}}</el-form-item>
<el-form-item label="升级地址:">
<a target="_blank" :href="upgradeInfo.upgradeUrl">{{upgradeInfo.upgradeUrl}}</a>
</el-form-item>
<el-form-item label="升级内容:">{{upgradeInfo.upgradeContent}}</el-form-item>
</template>
<el-form-item label="">
欢迎加群讨论QQ群号466363173欢迎提交需求欢迎使用和加入开发
</el-form-item>
</el-form>
</el-dialog>
</div>
</body>
<script type="text/javascript" src="webjars/doc-dubbo/vue/vue.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/element-ui.js"></script>
<!-- ajax 用到了jquery -->
<script type="text/javascript" src="webjars/doc-dubbo/js/jquery-3.1.0.min.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/common.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/toast.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/formatjson.js"></script>
<script type="text/javascript" src="webjars/doc-dubbo/js/doc-dubbo-tree.js"></script>
<script>
var app = new Vue({
el: '#app',
data() {
return {
isCollapse: false,
aboutDialogVisible: false,
onlineDebugLoading: false,
pathIndex: [],
defaultProps: {
children: 'children',
label: 'label'
},
// 展示的信息
dubboInfo: {},
dubboInfoExplainShow: true,
docInfoExplainInput: "",
dubboInfoResultShow: true,
docInfoResultInput: "",
// 请求的IP端口下拉选项
requestHostOptions: [],
requestHostValue: "",
requestResult: "",
// 依据目录树存储的map全局对象
treePathDataMap: new Map(),
// dubbo列表
dubboDocList: [],
dubboDocMap: [],
// 搜索的输入内容
searchKeywords: "",
docParamList: [],
docParamRequestList: [],
// 参数类型选项
paramTypeOptions: [{
value: 'java.lang.String'
}, {
value: 'java.lang.Long'
}, {
value: 'java.lang.Integer'
}],
paramTypeValue: "java.lang.String",
// 升级信息
upgradeInfo: {},
}
},
watch: {
},
mounted: function () {
// 无论发布在哪、如何修改源码,请勿删除本行原作者信息,感谢
console.log("%c项目信息\n开发者列表暮光城中城\n项目地址https://gitee.com/zyplayer/zyplayer-doc", "color:red");
this.doGetServiceList();
this.checkSystemUpgrade();
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
handleNodeClick(data) {
if (data.children == null) {
console.log(data);
var path = data.interface;
var application = data.application;
var docInfo = app.dubboDocMap[path];
if (!!docInfo) {
this.createDocInfo(path, data.method);
} else {
var service = path.substring(0, path.lastIndexOf("."));
var method = path.substring(path.lastIndexOf(".") + 1, path.length);
var param = {service: service, method: method, application: application};
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/findDocInfo", "post", "json", param, function (json) {
if (validateResult(json)) {
if (!!json.data) {
app.dubboDocMap[json.data.function] = json.data;
}
app.createDocInfo(path, method);
}
});
}
//console.log(app.dubboInfo);
}
},
createDocInfo(path, method) {
var docInfo = app.dubboDocMap[path];
var dubboInfo = app.treePathDataMap.get(path);
dubboInfo.method = method;
dubboInfo.function = path;
dubboInfo.docInfo = docInfo || {};
// 清空再赋值才会重新渲染
app.dubboInfo = {};
app.dubboInfo = dubboInfo;
app.docInfoExplainInput = dubboInfo.docInfo.explain;
app.docParamList = [];
app.docParamList = dubboInfo.docInfo.params || [];
this.createDocParamRequestList();
// 请求相关
app.requestResult = "";
app.requestHostValue = "";
app.requestHostOptions = [];
for (var i = 0; i < dubboInfo.nodeList.length; i++) {
var item = dubboInfo.nodeList[i];
app.requestHostOptions.push({
value: item.ip + ":" + item.port
});
}
if (app.requestHostOptions.length > 0) {
app.requestHostValue = app.requestHostOptions[0].value;
}
},
reloadService(){
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/reloadService", "post", "json", {}, function (json) {
if (validateResult(json)) {
app.$message({
message: '加载成功!',
type: 'success'
});
app.doGetServiceList();
}
});
},
searchByKeywords() {
app.pathIndex = createTreeViewByTreeWithMerge(app.dubboDocList, app.searchKeywords);
},
doGetServiceList() {
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/getDocList", "post", "json", {}, function (json) {
if (validateResult(json)) {
app.dubboDocList = json.data.serverList || [];
app.dubboDocMap = json.data.docMap || {};
app.pathIndex = createTreeViewByTreeWithMerge(app.dubboDocList);
}
});
},
saveDocInfoExplain(){
this.doSaveDocInfo(app.docInfoExplainInput, null, null, true);
},
saveDocInfoResult(){
this.doSaveDocInfo(null, null, app.docInfoResultInput, true);
},
saveDocInfoParam() {
var docParamList = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
if (isNotEmpty(item.paramType)) {
docParamList.push(item);
}
}
var paramsJson = JSON.stringify(docParamList);
this.doSaveDocInfo(null, paramsJson, null, true);
},
createDocParamRequestList() {
var docParamList = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
if (isNotEmpty(item.paramType) || isNotEmpty(item.paramDesc)) {
docParamList.push(item);
}
}
app.docParamRequestList = docParamList;
},
doSaveDocInfo(explain, params, result, showSuccess){
var param = {
service: app.dubboInfo.interface,
method: app.dubboInfo.method,
resultType: app.dubboInfo.resultType,
paramValue: app.dubboInfo.paramValue,
version: app.dubboInfo.docInfo.version || 0,
explain: explain,
result: result,
paramsJson: params,
};
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/saveDoc", "post", "json", param, function (json) {
if (validateResult(json)) {
app.dubboDocMap[json.data.function] = json.data;
app.dubboInfo.docInfo = json.data;
app.dubboInfoExplainShow = true;
app.dubboInfoResultShow = true;
app.docParamList = json.data.params || [];
app.createDocParamRequestList();
if (showSuccess) {
Toast.success("保存成功!");
}
}
});
},
addDocParam() {
var leadAdd = app.docParamList.length <= 0;
if (!leadAdd) {
var last = app.docParamList[app.docParamList.length - 1];
if (isNotEmpty(last.paramType) || isNotEmpty(last.paramDesc)) {
leadAdd = true;
}
}
if (leadAdd) {
app.docParamList.push({
paramName: '',
paramType: '',
paramDesc: '',
paramValue: '',
});
}
},
requestExecute() {
var fuc = app.dubboInfo.function;
var hostValue = app.requestHostValue;
var service = fuc.substring(0, fuc.lastIndexOf("."));
var method = fuc.substring(fuc.lastIndexOf(".") + 1, fuc.length);
var ip = hostValue.substring(0, hostValue.lastIndexOf(":"));
var port = hostValue.substring(hostValue.lastIndexOf(":") + 1, hostValue.length);
var paramTypes = [];
var params = [];
for (var i = 0; i < app.docParamList.length; i++) {
var item = app.docParamList[i];
if (isNotEmpty(item.paramType) && isNotEmpty(item.paramValue)) {
paramTypes.push(item.paramType);
params.push(item.paramValue);
}
}
var param = {
service: service,
method: method,
ip: ip,
port: port,
paramTypes: JSON.stringify(paramTypes),
params: JSON.stringify(params),
};
app.requestResult = "";
app.onlineDebugLoading = true;
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/request", "post", "json", param, function (json) {
app.onlineDebugLoading = false;
if (json.errCode == 200) {
try {
app.requestResult = Formatjson.processObjectToHtmlPre(JSON.parse(json.data), 0, false, false, false, false);
} catch (e) {
try {
app.requestResult = Formatjson.processObjectToHtmlPre(json.data, 0, false, false, false, false);
} catch (e) {
app.requestResult = json.data;
}
}
var paramsJson = JSON.stringify(app.docParamRequestList);
app.doSaveDocInfo(null, paramsJson, null, false);
} else {
app.requestResult = json.errMsg;
}
});
},
checkSystemUpgrade() {
ajaxTemp("system/info/upgrade", "post", "json", {}, function (json) {
if (json.errCode == 200 && !!json.data) {
app.upgradeInfo = json.data;
console.log("zyplayer-doc发现新版本"
+ "\n升级地址" + json.data.upgradeUrl
+ "\n当前版本" + json.data.nowVersion
+ "\n最新版本" + json.data.lastVersion
+ "\n升级内容" + json.data.upgradeContent
);
}
});
},
}
});
</script>
<style>
html,body,#app {
margin: 0;
padding: 0;
height: 100%;
}
pre{margin: 0;}
.el-menu {
box-sizing: border-box;
border-right: 0;
margin-right: 3px;
}
.el-tree{
margin-right: 3px;
}
.el-tree-node__content{
padding-right: 20px;
}
.el-tabs--border-card>.el-tabs__content{
height: calc(100vh - 100px);overflow-y: auto;
}
.logo{
background: linear-gradient(-90deg, #03DDE4 0%, #30AFED 51%, #8755FF 100%); cursor: pointer;
width: 100%; height:60px;line-height:60px;font-size: 25px;color: #fff;text-align: center;
}
</style>
</html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon-dubbo.png><title>DUBBO文档管理</title><link href=css/app.b311b071.css rel=preload as=style><link href=css/chunk-vendors.7998ce0c.css rel=preload as=style><link href=js/app.393d2924.js rel=preload as=script><link href=js/chunk-vendors.3d65a5e1.js rel=preload as=script><link href=css/chunk-vendors.7998ce0c.css rel=stylesheet><link href=css/app.b311b071.css rel=stylesheet></head><body><noscript><strong>We're sorry but zyplayer-dubbo-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.3d65a5e1.js></script><script src=js/app.393d2924.js></script></body></html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long