mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-12-01 19:48:14 +08:00
feat(plugin): support for new plugin manager
This commit is contained in:
parent
a08400d0cc
commit
c28f20dc1c
@ -425,6 +425,15 @@ common.reset=Reset
|
||||
common.cropper=Crop
|
||||
common.tip.pageNotNetwork=Oops! Unable to connect to the network. Please check your connection!
|
||||
common.store=Store
|
||||
common.author=Author
|
||||
common.releasedTime=Released Time
|
||||
common.install=Install
|
||||
common.uninstall=Uninstall
|
||||
common.plugin.version=Plugin Version
|
||||
common.plugin.systemVersion=Current system version:
|
||||
common.plugin.list.name=Plugin List
|
||||
common.plugin.list.description=List of available plugins
|
||||
common.plugin.list.supportVersion=Support Version
|
||||
|
||||
## User i18n
|
||||
user.common.username=Username
|
||||
|
@ -425,6 +425,15 @@ common.reset=重置
|
||||
common.cropper=裁剪
|
||||
common.tip.pageNotNetwork=哎呀!无法连接到网络,请检查网络是否正常!
|
||||
common.store=商店
|
||||
common.author=作者
|
||||
common.releasedTime=发布时间
|
||||
common.install=安装
|
||||
common.uninstall=卸载
|
||||
common.plugin.version=插件版本
|
||||
common.plugin.systemVersion=当前系统版本:
|
||||
common.plugin.list.name=插件列表
|
||||
common.plugin.list.description=可用的插件列表
|
||||
common.plugin.list.supportVersion=支持的版本
|
||||
|
||||
## User i18n
|
||||
user.common.username=用户名
|
||||
|
31
configure/metadata.json
Normal file
31
configure/metadata.json
Normal file
@ -0,0 +1,31 @@
|
||||
[
|
||||
{
|
||||
"key": "plugin",
|
||||
"label": "common.plugin.list.name",
|
||||
"description": "common.plugin.list.description",
|
||||
"i18nFormat": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "MySQL",
|
||||
"label": "MySQL",
|
||||
"description": "Integrate MySQL data sources",
|
||||
"i18nFormat": true,
|
||||
"type": "JDBC",
|
||||
"version": "2024.4.0",
|
||||
"author": "datacap-community",
|
||||
"logo": "https://www.vectorlogo.zone/logos/mysql/mysql-icon.svg",
|
||||
"released": "2024-01-01",
|
||||
"supportVersion": [
|
||||
"8.0",
|
||||
"5.7"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "connector",
|
||||
"label": "common.connector.list.name",
|
||||
"description": "common.connector.list.description",
|
||||
"i18nFormat": true
|
||||
}
|
||||
]
|
53
core/datacap-plugin/pom.xml
Normal file
53
core/datacap-plugin/pom.xml
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap</artifactId>
|
||||
<version>2024.4.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>datacap-plugin</artifactId>
|
||||
<description>DataCap - Plugin Core</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
<version>3.9.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- 支持获取当前插件的版本 -->
|
||||
<!-- Support getting the current plugin version -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,7 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
public interface Plugin
|
||||
{
|
||||
String name();
|
||||
String version();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class PluginConfig
|
||||
{
|
||||
private Path pluginsDir;
|
||||
private boolean autoReload;
|
||||
private long scanInterval;
|
||||
private String pluginConfigFile;
|
||||
|
||||
public static PluginConfig defaultConfig()
|
||||
{
|
||||
return PluginConfig.builder()
|
||||
.pluginsDir(Paths.get("plugins"))
|
||||
.autoReload(false)
|
||||
.scanInterval(5000)
|
||||
.pluginConfigFile("plugin.properties")
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class PluginInfo
|
||||
{
|
||||
private String name;
|
||||
private String version;
|
||||
private Path location;
|
||||
private PluginState state;
|
||||
private ClassLoader classLoader;
|
||||
private Object instance;
|
||||
private Set<String> dependencies;
|
||||
private long loadTime;
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import io.edurt.datacap.plugin.loader.CompiledPomPluginLoader;
|
||||
import io.edurt.datacap.plugin.loader.DirectoryPluginLoader;
|
||||
import io.edurt.datacap.plugin.loader.PluginLoader;
|
||||
import io.edurt.datacap.plugin.loader.PluginLoaderFactory;
|
||||
import io.edurt.datacap.plugin.loader.PomPluginLoader;
|
||||
import io.edurt.datacap.plugin.loader.SPIPluginLoader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
public class PluginManager
|
||||
{
|
||||
// 插件配置
|
||||
// Plugin configuration
|
||||
private final PluginConfig config;
|
||||
|
||||
// 插件存储映射
|
||||
// Plugin storage mapping
|
||||
private final Map<String, PluginInfo> plugins;
|
||||
|
||||
// Guice注入器
|
||||
// Guice injector
|
||||
private final Injector injector;
|
||||
|
||||
// 插件加载器列表
|
||||
// Plugin loaders list
|
||||
private final List<PluginLoader> loaders;
|
||||
|
||||
// 运行状态标志
|
||||
// Running state flag
|
||||
private volatile boolean running;
|
||||
|
||||
public PluginManager(PluginConfig config)
|
||||
{
|
||||
this.config = config;
|
||||
this.plugins = Maps.newConcurrentMap();
|
||||
this.injector = Guice.createInjector(new PluginModule());
|
||||
|
||||
// 注册插件加载器
|
||||
// Register plugin loaders
|
||||
this.loaders = List.of(
|
||||
new SPIPluginLoader(),
|
||||
new PomPluginLoader(),
|
||||
new DirectoryPluginLoader(),
|
||||
new CompiledPomPluginLoader()
|
||||
);
|
||||
}
|
||||
|
||||
// 启动插件管理器
|
||||
// Start plugin manager
|
||||
public void start()
|
||||
{
|
||||
running = true;
|
||||
createPluginsDirectoryIfNotExists();
|
||||
loadPlugins();
|
||||
|
||||
if (config.isAutoReload()) {
|
||||
startPluginWatcher();
|
||||
}
|
||||
}
|
||||
|
||||
// 停止插件管理器
|
||||
// Stop plugin manager
|
||||
public void stop()
|
||||
{
|
||||
running = false;
|
||||
plugins.values().forEach(this::closePluginClassLoader);
|
||||
plugins.clear();
|
||||
}
|
||||
|
||||
// 创建插件目录(如果不存在)
|
||||
// Create plugins directory if not exists
|
||||
private void createPluginsDirectoryIfNotExists()
|
||||
{
|
||||
try {
|
||||
Files.createDirectories(config.getPluginsDir());
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.warn("Failed to create plugins directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 加载所有插件
|
||||
// Load all plugins
|
||||
private void loadPlugins()
|
||||
{
|
||||
try (Stream<Path> paths = Files.walk(config.getPluginsDir(), 1)) {
|
||||
paths.filter(Files::isDirectory)
|
||||
.peek(path -> log.info("Scanning plugin directory: {}", path))
|
||||
.filter(path -> !path.equals(config.getPluginsDir()))
|
||||
.forEach(this::loadPluginFromDirectory);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Failed to scan plugins directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 从目录加载插件
|
||||
// Load plugin from directory
|
||||
private void loadPluginFromDirectory(Path pluginDir)
|
||||
{
|
||||
try {
|
||||
List<PluginModule> modules = PluginLoaderFactory.loadPlugins(pluginDir);
|
||||
|
||||
for (PluginModule module : modules) {
|
||||
String pluginName = module.getName();
|
||||
log.info("Found plugin module: [ {} ] type [ {} ]", pluginName, module.getType());
|
||||
|
||||
PluginInfo pluginInfo = PluginInfo.builder()
|
||||
.name(pluginName)
|
||||
.version(module.getVersion())
|
||||
.location(pluginDir)
|
||||
.state(PluginState.CREATED)
|
||||
.classLoader(module.getClass().getClassLoader())
|
||||
.instance(module)
|
||||
.loadTime(System.currentTimeMillis())
|
||||
.build();
|
||||
|
||||
// 移除旧版本插件
|
||||
// Remove old version plugin
|
||||
PluginInfo oldPlugin = plugins.remove(pluginName);
|
||||
if (oldPlugin != null) {
|
||||
closePluginClassLoader(oldPlugin);
|
||||
}
|
||||
|
||||
plugins.put(pluginName, pluginInfo);
|
||||
log.info("Successfully loaded plugin: [ {} ] from directory [ {} ]",
|
||||
pluginName, pluginDir);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to load plugin from directory: {}", pluginDir, e);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭插件类加载器
|
||||
// Close plugin class loader
|
||||
private void closePluginClassLoader(PluginInfo pluginInfo)
|
||||
{
|
||||
try {
|
||||
if (pluginInfo.getClassLoader() instanceof URLClassLoader) {
|
||||
((URLClassLoader) pluginInfo.getClassLoader()).close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Failed to close plugin classloader: {}", pluginInfo.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 启动插件监视器线程
|
||||
// Start plugin watcher thread
|
||||
private void startPluginWatcher()
|
||||
{
|
||||
Thread watchThread = new Thread(() -> {
|
||||
while (running) {
|
||||
try {
|
||||
Thread.sleep(config.getScanInterval());
|
||||
loadPlugins();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
watchThread.setDaemon(true);
|
||||
watchThread.start();
|
||||
}
|
||||
|
||||
// 获取指定名称的插件
|
||||
// Get plugin by name
|
||||
public Optional<PluginModule> getPlugin(String name)
|
||||
{
|
||||
return Optional.ofNullable(plugins.get(name))
|
||||
.map(info -> (PluginModule) info.getInstance());
|
||||
}
|
||||
|
||||
// 获取所有插件信息
|
||||
// Get all plugin information
|
||||
public List<PluginInfo> getPluginInfos()
|
||||
{
|
||||
return new ArrayList<>(plugins.values());
|
||||
}
|
||||
|
||||
// 卸载指定名称的插件
|
||||
// Unload plugin by name
|
||||
public boolean unloadPlugin(String name)
|
||||
{
|
||||
PluginInfo pluginInfo = plugins.remove(name);
|
||||
if (pluginInfo != null) {
|
||||
closePluginClassLoader(pluginInfo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
public class PluginModule
|
||||
extends AbstractModule
|
||||
{
|
||||
String getName()
|
||||
{
|
||||
return this.getClass().getSimpleName()
|
||||
.replace("PluginModule", "")
|
||||
.replace("Module", "");
|
||||
}
|
||||
|
||||
String getVersion()
|
||||
{
|
||||
return this.getClass()
|
||||
.getPackage()
|
||||
.getImplementationVersion();
|
||||
}
|
||||
|
||||
String getType()
|
||||
{
|
||||
return "Plugin";
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
public enum PluginState
|
||||
{
|
||||
CREATED,
|
||||
INITIALIZED,
|
||||
STARTED,
|
||||
STOPPED,
|
||||
FAILED
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
public class CompiledPomPluginLoader
|
||||
implements PluginLoader
|
||||
{
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "CompiledPom";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginModule> load(Path path)
|
||||
{
|
||||
try {
|
||||
// 处理传入的是pom.xml文件的情况
|
||||
// Handle the case when input is pom.xml file
|
||||
Path pomFile;
|
||||
if (path.toString().endsWith("pom.xml")) {
|
||||
pomFile = path;
|
||||
path = path.getParent();
|
||||
}
|
||||
else {
|
||||
pomFile = path.resolve("pom.xml");
|
||||
}
|
||||
|
||||
if (!Files.exists(pomFile)) {
|
||||
log.debug("No pom.xml found in {}", path);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// 读取POM文件
|
||||
// Read POM file
|
||||
MavenXpp3Reader reader = new MavenXpp3Reader();
|
||||
Model model = reader.read(new FileReader(pomFile.toFile()));
|
||||
|
||||
// 获取编译后的类路径
|
||||
// Get compiled classpath
|
||||
Path targetClasses = path.resolve("target/classes");
|
||||
Path targetDependencies = path.resolve("target/dependency");
|
||||
|
||||
// 如果已编译的类不存在,直接返回空列表
|
||||
// If compiled classes don't exist, return empty list
|
||||
if (!Files.exists(targetClasses)) {
|
||||
log.debug("Target classes directory not found: {}", targetClasses);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// 创建类加载器
|
||||
// Create class loader
|
||||
URLClassLoader classLoader = createProjectClassLoader(targetClasses, targetDependencies);
|
||||
|
||||
// 查找并加载插件类
|
||||
// Find and load plugin classes
|
||||
return findAndLoadPlugins(classLoader, targetClasses);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to load compiled plugin from: {}", path, e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建项目类加载器
|
||||
// Create project class loader
|
||||
private URLClassLoader createProjectClassLoader(Path targetClasses, Path targetDependencies)
|
||||
throws Exception
|
||||
{
|
||||
List<URL> urls = new ArrayList<>();
|
||||
|
||||
// 添加编译后的类路径
|
||||
// Add compiled classes path
|
||||
log.debug("Adding classes directory to classpath: {}", targetClasses);
|
||||
urls.add(targetClasses.toUri().toURL());
|
||||
|
||||
// 添加所有依赖jar(如果存在)
|
||||
// Add all dependency jars (if exist)
|
||||
if (Files.exists(targetDependencies)) {
|
||||
log.debug("Adding dependencies from: {}", targetDependencies);
|
||||
try (Stream<Path> paths = Files.walk(targetDependencies)) {
|
||||
paths.filter(path -> path.toString().endsWith(".jar"))
|
||||
.forEach(path -> {
|
||||
try {
|
||||
log.debug("Adding dependency to classpath: {}", path);
|
||||
urls.add(path.toUri().toURL());
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to add dependency jar to classpath: {}", path, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.debug("Dependencies directory not found: {}", targetDependencies);
|
||||
}
|
||||
|
||||
return new URLClassLoader(
|
||||
urls.toArray(new URL[0]),
|
||||
getClass().getClassLoader()
|
||||
);
|
||||
}
|
||||
|
||||
// 查找并加载插件类
|
||||
// Find and load plugin classes
|
||||
private List<PluginModule> findAndLoadPlugins(URLClassLoader classLoader, Path targetClasses)
|
||||
{
|
||||
List<PluginModule> plugins = new ArrayList<>();
|
||||
try {
|
||||
// 扫描编译后的类文件
|
||||
// Scan compiled class files
|
||||
try (Stream<Path> paths = Files.walk(targetClasses)) {
|
||||
paths.filter(path -> path.toString().endsWith(".class"))
|
||||
.filter(path -> !path.toString().contains("$"))
|
||||
.forEach(path -> {
|
||||
try {
|
||||
String className = getClassName(targetClasses, path);
|
||||
Class<?> cls = classLoader.loadClass(className);
|
||||
|
||||
// 检查是否是具体的插件类
|
||||
// Check if it's a concrete plugin class
|
||||
if (PluginModule.class.isAssignableFrom(cls) &&
|
||||
!cls.isInterface() &&
|
||||
!Modifier.isAbstract(cls.getModifiers())) {
|
||||
PluginModule plugin = (PluginModule) cls.getDeclaredConstructor().newInstance();
|
||||
plugins.add(plugin);
|
||||
log.info("Loaded plugin class: {}", className);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to load class: {}", path, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to scan for plugin classes", e);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
// 获取类名
|
||||
// Get class name
|
||||
private String getClassName(Path baseDir, Path classFile)
|
||||
{
|
||||
String relativePath = baseDir.relativize(classFile).toString();
|
||||
return relativePath.replace(File.separatorChar, '.')
|
||||
.replace(".class", "");
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
import io.edurt.datacap.plugin.utils.PluginClassLoaderUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class DirectoryPluginLoader
|
||||
implements PluginLoader
|
||||
{
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "Directory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginModule> load(Path path)
|
||||
{
|
||||
try {
|
||||
URLClassLoader classLoader = PluginClassLoaderUtils.createClassLoader(path);
|
||||
return Files.walk(path)
|
||||
.filter(p -> p.toString().endsWith(".class"))
|
||||
.filter(p -> !p.toString().contains("$"))
|
||||
.map(p -> loadClass(classLoader, p))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to load plugins from directory: {}", path, e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<PluginModule> loadClass(URLClassLoader classLoader, Path classFile)
|
||||
{
|
||||
try {
|
||||
String className = getClassName(classFile);
|
||||
Class<?> cls = classLoader.loadClass(className);
|
||||
|
||||
if (PluginModule.class.isAssignableFrom(cls)) {
|
||||
return Optional.of((PluginModule) cls.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to load class: {}", classFile, e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private String getClassName(Path classFile)
|
||||
{
|
||||
String path = classFile.toString();
|
||||
return path.substring(path.indexOf("io/edurt"))
|
||||
.replace("/", ".")
|
||||
.replace(".class", "");
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public interface PluginLoader
|
||||
{
|
||||
// 获取加载器类型
|
||||
// Get loader type
|
||||
String getType();
|
||||
|
||||
// 加载插件
|
||||
// Load plugins
|
||||
List<PluginModule> load(Path path);
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
public class PluginLoaderFactory
|
||||
{
|
||||
// 用于缓存已注册的加载器
|
||||
// Cache for registered loaders
|
||||
private static final Map<String, PluginLoader> loaderRegistry = new ConcurrentHashMap<>();
|
||||
|
||||
// 注册默认的加载器
|
||||
// Register default loaders
|
||||
static {
|
||||
registerLoader(new SPIPluginLoader());
|
||||
registerLoader(new PomPluginLoader());
|
||||
registerLoader(new DirectoryPluginLoader());
|
||||
registerLoader(new CompiledPomPluginLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个新的插件加载器
|
||||
* Register a new plugin loader
|
||||
*
|
||||
* @param loader 要注册的加载器
|
||||
* @param loader the loader to register
|
||||
*/
|
||||
public static void registerLoader(PluginLoader loader)
|
||||
{
|
||||
String type = loader.getType();
|
||||
if (type == null || type.trim().isEmpty()) {
|
||||
log.warn("Attempted to register loader with null or empty type: {}", loader.getClass().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
PluginLoader existing = loaderRegistry.putIfAbsent(type.toLowerCase(), loader);
|
||||
if (existing != null) {
|
||||
log.warn("Loader type '{}' is already registered, skipping registration of {}",
|
||||
type, loader.getClass().getName());
|
||||
}
|
||||
else {
|
||||
log.info("Registered plugin loader: {} for type: {}", loader.getClass().getName(), type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据类型获取加载器
|
||||
* Get loader by type
|
||||
*
|
||||
* @param type 加载器类型
|
||||
* @param type loader type
|
||||
* @return 对应的加载器实例,如果未找到则返回null
|
||||
* @return corresponding loader instance, or null if not found
|
||||
*/
|
||||
public static PluginLoader getLoader(String type)
|
||||
{
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
return loaderRegistry.get(type.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用所有已注册的加载器尝试加载插件
|
||||
* Attempt to load plugins using all registered loaders
|
||||
*
|
||||
* @param pluginDir 插件目录
|
||||
* @param pluginDir plugin directory
|
||||
* @return 加载的插件模块列表
|
||||
* @return list of loaded plugin modules
|
||||
*/
|
||||
public static List<PluginModule> loadPlugins(Path pluginDir)
|
||||
{
|
||||
if (pluginDir == null) {
|
||||
log.warn("Plugin directory is null");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 遍历所有注册的加载器尝试加载
|
||||
// Iterate through all registered loaders to attempt loading
|
||||
for (Map.Entry<String, PluginLoader> entry : loaderRegistry.entrySet()) {
|
||||
String type = entry.getKey();
|
||||
PluginLoader loader = entry.getValue();
|
||||
|
||||
try {
|
||||
List<PluginModule> modules = loader.load(pluginDir);
|
||||
if (modules != null && !modules.isEmpty()) {
|
||||
log.info("Successfully loaded {} plugin(s) using loader type: {}", modules.size(), type);
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to load plugins using loader type '{}': {}", type, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("No plugins could be loaded from directory: {}", pluginDir);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已注册的加载器类型
|
||||
* Get all registered loader types
|
||||
*
|
||||
* @return 加载器类型列表
|
||||
* @return list of loader types
|
||||
*/
|
||||
public static List<String> getRegisteredTypes()
|
||||
{
|
||||
return Collections.unmodifiableList(
|
||||
new ArrayList<>(loaderRegistry.keySet())
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
import io.edurt.datacap.plugin.utils.PluginClassLoaderUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class PomPluginLoader
|
||||
implements PluginLoader
|
||||
{
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "Pom";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginModule> load(Path path)
|
||||
{
|
||||
try {
|
||||
Path pomFile = path.resolve("pom.xml");
|
||||
if (!Files.exists(pomFile)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
MavenXpp3Reader reader = new MavenXpp3Reader();
|
||||
Model model = reader.read(new FileReader(pomFile.toFile()));
|
||||
|
||||
String mainClass = model.getProperties().getProperty("plugin.class");
|
||||
if (mainClass == null) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
URLClassLoader classLoader = PluginClassLoaderUtils.createClassLoader(path);
|
||||
Class<?> pluginClass = classLoader.loadClass(mainClass);
|
||||
|
||||
if (!PluginModule.class.isAssignableFrom(pluginClass)) {
|
||||
log.error("Class {} does not implement PluginModule", mainClass);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
PluginModule plugin = (PluginModule) pluginClass.getDeclaredConstructor().newInstance();
|
||||
return List.of(plugin);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to load plugins using POM from: {}", path, e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package io.edurt.datacap.plugin.loader;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
import io.edurt.datacap.plugin.utils.PluginClassLoaderUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@Slf4j
|
||||
public class SPIPluginLoader
|
||||
implements PluginLoader
|
||||
{
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return "SPI";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PluginModule> load(Path path)
|
||||
{
|
||||
try {
|
||||
URLClassLoader classLoader = PluginClassLoaderUtils.createClassLoader(path);
|
||||
ServiceLoader<PluginModule> serviceLoader = ServiceLoader.load(PluginModule.class, classLoader);
|
||||
return StreamSupport.stream(serviceLoader.spliterator(), false)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Failed to load plugins using SPI from: {}", path, e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.edurt.datacap.plugin.utils;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PluginClassLoaderUtils
|
||||
{
|
||||
public static URLClassLoader createClassLoader(Path directory)
|
||||
throws Exception
|
||||
{
|
||||
List<URL> urls = new ArrayList<>();
|
||||
|
||||
// Add all JARs in the directory
|
||||
if (Files.isDirectory(directory)) {
|
||||
Files.walk(directory)
|
||||
.filter(path -> path.toString().endsWith(".jar"))
|
||||
.forEach(path -> {
|
||||
try {
|
||||
urls.add(path.toUri().toURL());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new URLClassLoader(
|
||||
urls.toArray(new URL[0]),
|
||||
PluginClassLoaderUtils.class.getClassLoader()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,253 @@
|
||||
package io.edurt.datacap.plugin.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
public class PluginPathUtils
|
||||
{
|
||||
// 项目根目录标志文件/目录
|
||||
// Project root markers
|
||||
private static final List<String> PROJECT_ROOT_MARKERS = Arrays.asList(
|
||||
"pom.xml", // Maven项目标志
|
||||
"build.gradle", // Gradle项目标志
|
||||
".git", // Git仓库标志
|
||||
".gitignore", // Git配置标志
|
||||
".idea", // IDEA项目标志
|
||||
"mvnw", // Maven包装器标志
|
||||
"gradlew" // Gradle包装器标志
|
||||
);
|
||||
|
||||
// 模块目录标志
|
||||
// Module directory markers
|
||||
private static final List<String> MODULE_MARKERS = Arrays.asList(
|
||||
"src/main/java",
|
||||
"src/main/resources",
|
||||
"src/test/java",
|
||||
"target/classes",
|
||||
"build/classes"
|
||||
);
|
||||
|
||||
/**
|
||||
* 查找项目根目录
|
||||
* Find project root directory
|
||||
*
|
||||
* @return 项目根目录的Path对象
|
||||
* @return Path object of project root directory
|
||||
*/
|
||||
public static Path findProjectRoot()
|
||||
{
|
||||
Path rootPath = null;
|
||||
|
||||
// 1. 首先尝试从类加载路径查找
|
||||
// First try to find from class loading path
|
||||
try {
|
||||
String className = PluginPathUtils.class.getName().replace('.', '/') + ".class";
|
||||
URL classUrl = PluginPathUtils.class.getClassLoader().getResource(className);
|
||||
|
||||
if (classUrl != null) {
|
||||
String classPath = classUrl.getPath();
|
||||
// 处理JAR文件路径
|
||||
// Handle JAR file path
|
||||
if (classPath.contains(".jar!")) {
|
||||
classPath = classPath.substring(0, classPath.indexOf(".jar!") + 4);
|
||||
}
|
||||
|
||||
Path path = Paths.get(new File(classPath).toURI());
|
||||
log.debug("Starting search from class path: {}", path);
|
||||
rootPath = findRootFromPath(path);
|
||||
|
||||
if (rootPath != null) {
|
||||
log.info("Found project root from class path: {}", rootPath);
|
||||
return rootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to find root from class path", e);
|
||||
}
|
||||
|
||||
// 2. 尝试从当前工作目录查找
|
||||
// Try to find from current working directory
|
||||
try {
|
||||
Path currentPath = Paths.get("").toAbsolutePath();
|
||||
log.debug("Starting search from current directory: {}", currentPath);
|
||||
rootPath = findRootFromPath(currentPath);
|
||||
|
||||
if (rootPath != null) {
|
||||
log.info("Found project root from current directory: {}", rootPath);
|
||||
return rootPath;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to find root from current directory", e);
|
||||
}
|
||||
|
||||
// 3. 尝试从系统属性user.dir查找
|
||||
// Try to find from system property user.dir
|
||||
try {
|
||||
String userDir = System.getProperty("user.dir");
|
||||
if (userDir != null) {
|
||||
Path userPath = Paths.get(userDir);
|
||||
log.debug("Starting search from user.dir: {}", userPath);
|
||||
rootPath = findRootFromPath(userPath);
|
||||
|
||||
if (rootPath != null) {
|
||||
log.info("Found project root from user.dir: {}", rootPath);
|
||||
return rootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to find root from user.dir", e);
|
||||
}
|
||||
|
||||
// 4. 如果都找不到,向上遍历所有父目录
|
||||
// If not found, traverse all parent directories
|
||||
try {
|
||||
Path currentPath = Paths.get("").toAbsolutePath();
|
||||
while (currentPath != null && currentPath.getParent() != null) {
|
||||
if (isProjectRoot(currentPath)) {
|
||||
log.info("Found project root from parent traversal: {}", currentPath);
|
||||
return currentPath;
|
||||
}
|
||||
currentPath = currentPath.getParent();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Failed to find root from parent traversal", e);
|
||||
}
|
||||
|
||||
// 5. 最后返回当前目录作为后备方案
|
||||
// Finally return current directory as fallback
|
||||
Path fallback = Paths.get("").toAbsolutePath();
|
||||
log.warn("Could not find project root, using fallback: {}", fallback);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定路径向上查找项目根目录
|
||||
* Find project root directory from specified path
|
||||
*
|
||||
* @param startPath 开始搜索的路径
|
||||
* @param startPath path to start search from
|
||||
* @return 项目根目录路径,如果未找到返回null
|
||||
* @return project root path, null if not found
|
||||
*/
|
||||
private static Path findRootFromPath(Path startPath)
|
||||
{
|
||||
try {
|
||||
Path currentPath = startPath;
|
||||
while (currentPath != null && currentPath.getParent() != null) {
|
||||
// 如果当前目录是模块目录,继续向上查找
|
||||
// If current directory is a module directory, continue searching up
|
||||
if (isModuleDirectory(currentPath)) {
|
||||
currentPath = currentPath.getParent();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否是项目根目录
|
||||
// Check if it's project root directory
|
||||
if (isProjectRoot(currentPath)) {
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
currentPath = currentPath.getParent();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.debug("Error while searching for project root from path: {}", startPath, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定路径是否为项目根目录
|
||||
* Check if given path is project root directory
|
||||
*/
|
||||
private static boolean isProjectRoot(Path path)
|
||||
{
|
||||
try {
|
||||
// 检查是否存在任何根目录标志
|
||||
// Check if any root marker exists
|
||||
boolean hasRootMarker = PROJECT_ROOT_MARKERS.stream()
|
||||
.anyMatch(marker -> Files.exists(path.resolve(marker)));
|
||||
|
||||
if (!hasRootMarker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 额外检查是否有src目录或其他项目结构
|
||||
// Additional check for src directory or other project structure
|
||||
return Files.exists(path.resolve("src")) ||
|
||||
Files.exists(path.resolve("pom.xml")) ||
|
||||
Files.exists(path.resolve("build.gradle"));
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查给定路径是否为模块目录
|
||||
* Check if given path is module directory
|
||||
*/
|
||||
private static boolean isModuleDirectory(Path path)
|
||||
{
|
||||
return MODULE_MARKERS.stream()
|
||||
.anyMatch(marker -> Files.exists(path.resolve(marker)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析插件路径
|
||||
* Resolve plugin path
|
||||
*/
|
||||
public static Path resolvePluginPath(Path path)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new IllegalArgumentException("Path cannot be null");
|
||||
}
|
||||
|
||||
// 如果是绝对路径,直接返回
|
||||
// If absolute path, return directly
|
||||
if (path.isAbsolute()) {
|
||||
log.debug("Using absolute path: {}", path);
|
||||
return path;
|
||||
}
|
||||
|
||||
// 解析相对于项目根目录的路径
|
||||
// Resolve path relative to project root
|
||||
Path projectRoot = findProjectRoot();
|
||||
Path resolvedPath = projectRoot.resolve(path).normalize();
|
||||
log.debug("Resolved plugin path {} -> {}", path, resolvedPath);
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定路径中查找编译输出目录
|
||||
* Find compilation output directory from specified path
|
||||
*/
|
||||
public static Optional<Path> findOutputDirectory(Path projectPath)
|
||||
{
|
||||
try (Stream<Path> paths = Files.walk(projectPath, 3)) {
|
||||
return paths.filter(path -> path.endsWith("classes") ||
|
||||
path.endsWith("resources"))
|
||||
.filter(Files::exists)
|
||||
.findFirst();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.debug("Failed to find output directory for path: {}", projectPath, e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.edurt.datacap.plugin;
|
||||
|
||||
import io.edurt.datacap.plugin.utils.PluginPathUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PluginManagerTest
|
||||
{
|
||||
@Test
|
||||
public void testLoadPlugin()
|
||||
{
|
||||
Path projectRoot = PluginPathUtils.findProjectRoot();
|
||||
PluginConfig config = PluginConfig.builder()
|
||||
.pluginsDir(projectRoot.resolve("test/datacap-test-plugin"))
|
||||
.build();
|
||||
|
||||
PluginManager pluginManager = new PluginManager(config);
|
||||
pluginManager.start();
|
||||
|
||||
System.out.println(pluginManager.getPluginInfos());
|
||||
}
|
||||
}
|
@ -93,463 +93,463 @@
|
||||
<artifactId>datacap-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-mysql</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-clickhouse</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-presto</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-redis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-trino</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-postgresql</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-elasticsearch</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-druid</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-kyuubi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-hive</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-kylin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-ignite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-db2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-mongo</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-dremio</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-monetdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-phoenix</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-h2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-sqlserver</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-oracle</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-cratedb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-dm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http-cratedb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http-clickhouse</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-tdengine</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-impala</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-oceanbase</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-redis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-neo4j</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-iotdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-snowflake</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-ydb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-zookeeper</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-duckdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-alioss</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-kafka</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-h2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http-ceresdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http-greptime</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http-questdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-doris</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-starrocks</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-jdbc-hologres</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-native-hdfs</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-pinot</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-mongo-community</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-cassandra</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-matrixone</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-scylladb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-paradedb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-timescale</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-solr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin-influxdb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-captcha</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Fs -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-local</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-qiniu</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-alioss</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-tencent-cos</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-amazon-s3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-fs-minio</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-mysql</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-clickhouse</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-presto</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-redis</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-trino</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-postgresql</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-elasticsearch</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-druid</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-kyuubi</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-hive</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-kylin</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-ignite</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-db2</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <!– <dependency>–>-->
|
||||
<!-- <!– <groupId>io.edurt.datacap</groupId>–>-->
|
||||
<!-- <!– <artifactId>datacap-jdbc-mongo</artifactId>–>-->
|
||||
<!-- <!– <version>${project.version}</version>–>-->
|
||||
<!-- <!– </dependency>–>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-dremio</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-monetdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-phoenix</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-h2</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-sqlserver</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-oracle</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-cratedb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-dm</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-http-cratedb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-http-clickhouse</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-tdengine</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-impala</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-oceanbase</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-redis</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-neo4j</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-iotdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-snowflake</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-ydb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-zookeeper</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-duckdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-alioss</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-kafka</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-h2</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-http-ceresdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-http-greptime</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-http-questdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-doris</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-starrocks</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-jdbc-hologres</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-native-hdfs</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-pinot</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-mongo-community</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-cassandra</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-matrixone</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-scylladb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-paradedb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-timescale</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-solr</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-plugin-influxdb</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-captcha</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <!– Fs –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-spi</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-local</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-qiniu</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-alioss</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-tencent-cos</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-amazon-s3</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-fs-minio</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Notify -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-notify-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-notify-dingtalk</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-notify-dingtalk</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Parser -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-parser-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-parser-mysql</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-parser-trino</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-parser-mysql</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-parser-trino</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Executor -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-executor-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-executor-local</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-executor-seatunnel</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-executor-local</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-executor-seatunnel</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Scheduler -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-scheduler-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-scheduler-local</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-scheduler-local</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- Convert -->
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-spi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-csv</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-json</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-txt</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-convert-none</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-convert-csv</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-convert-json</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-convert-xml</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-convert-txt</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.edurt.datacap</groupId>-->
|
||||
<!-- <artifactId>datacap-convert-none</artifactId>-->
|
||||
<!-- <version>${project.version}</version>-->
|
||||
<!-- <scope>provided</scope>-->
|
||||
<!-- </dependency>-->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -7,8 +7,10 @@ import com.google.inject.TypeLiteral;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.executor.Executor;
|
||||
import io.edurt.datacap.scheduler.Scheduler;
|
||||
import io.edurt.datacap.spi.Plugin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
@ -43,4 +45,15 @@ public class PluginController
|
||||
plugins.put("scheduler", schedulers);
|
||||
return CommonResponse.success(plugins);
|
||||
}
|
||||
|
||||
@GetMapping(value = {"filter"})
|
||||
public CommonResponse getPluginByType(@RequestParam String type)
|
||||
{
|
||||
if (type.equalsIgnoreCase("plugin")) {
|
||||
return CommonResponse.success(injector.getInstance(Key.get(new TypeLiteral<Set<Plugin>>() {})));
|
||||
}
|
||||
else {
|
||||
return CommonResponse.failure("Unknown type " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,24 +37,24 @@ public class DatasetSchedulerInitializer
|
||||
throws Exception
|
||||
{
|
||||
log.info("Start dataset scheduler initializer");
|
||||
this.repository.findAllBySyncMode(SyncMode.TIMING)
|
||||
.forEach(item -> {
|
||||
log.info("Dataset [ {} ] will be scheduled", item.getName());
|
||||
SpiUtils.findSchedule(this.injector, item.getScheduler())
|
||||
.ifPresent(scheduler -> {
|
||||
SchedulerRequest request = new SchedulerRequest();
|
||||
request.setName(item.getId().toString());
|
||||
request.setGroup("datacap");
|
||||
request.setExpression(item.getExpression());
|
||||
request.setJobId(String.valueOf(item.getId()));
|
||||
request.setCreateBeforeDelete(true);
|
||||
if (scheduler.name().equals("Default")) {
|
||||
request.setJob(new DatasetJob());
|
||||
request.setScheduler(this.scheduler);
|
||||
}
|
||||
scheduler.initialize(request);
|
||||
});
|
||||
});
|
||||
// this.repository.findAllBySyncMode(SyncMode.TIMING)
|
||||
// .forEach(item -> {
|
||||
// log.info("Dataset [ {} ] will be scheduled", item.getName());
|
||||
// SpiUtils.findSchedule(this.injector, item.getScheduler())
|
||||
// .ifPresent(scheduler -> {
|
||||
// SchedulerRequest request = new SchedulerRequest();
|
||||
// request.setName(item.getId().toString());
|
||||
// request.setGroup("datacap");
|
||||
// request.setExpression(item.getExpression());
|
||||
// request.setJobId(String.valueOf(item.getId()));
|
||||
// request.setCreateBeforeDelete(true);
|
||||
// if (scheduler.name().equals("Default")) {
|
||||
// request.setJob(new DatasetJob());
|
||||
// request.setScheduler(this.scheduler);
|
||||
// }
|
||||
// scheduler.initialize(request);
|
||||
// });
|
||||
// });
|
||||
log.info("End dataset scheduler initializer");
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,28 @@ const createDefaultRouter = (router: any) => {
|
||||
]
|
||||
}
|
||||
router.addRoute(indexRouter)
|
||||
|
||||
const storeRouter = {
|
||||
path: '/',
|
||||
meta: {
|
||||
title: 'common.store',
|
||||
isRoot: true
|
||||
},
|
||||
component: LayoutContainer,
|
||||
redirect: '/store',
|
||||
children: [
|
||||
{
|
||||
name: 'store',
|
||||
path: 'store',
|
||||
meta: {
|
||||
title: 'common.store',
|
||||
isRoot: false
|
||||
},
|
||||
component: () => import('@/views/pages/store/StoreHome.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
router.addRoute(storeRouter)
|
||||
}
|
||||
|
||||
createSystemRouter(router)
|
||||
|
@ -7,7 +7,12 @@ class PluginService
|
||||
{
|
||||
getPlugins(): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().get(`${DEFAULT_PATH}`)
|
||||
return new HttpUtils().get(`${ DEFAULT_PATH }`)
|
||||
}
|
||||
|
||||
filterByType(type: string): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().get(`${ DEFAULT_PATH }/filter`, { type })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
# App.vue
|
||||
<template>
|
||||
<div class="flex h-screen bg-gray-100">
|
||||
<!-- 左侧组件面板 -->
|
||||
<BigScreenPanel />
|
||||
|
||||
<!-- 中间编辑区域 -->
|
||||
<BigScreenEditor
|
||||
ref="editorRef"
|
||||
:grid-size="20"
|
||||
:selected-id="selectedId"
|
||||
@select="handleSelect"
|
||||
@update:components="handleComponentsUpdate"
|
||||
/>
|
||||
|
||||
<!-- 右侧配置面板 -->
|
||||
<BigScreenConfigure
|
||||
:selected-component="selectedComponent"
|
||||
@update="handleConfigUpdate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import BigScreenPanel from './components/BigScreenPanel.vue'
|
||||
import BigScreenEditor from './components/BigScreenEditor.vue'
|
||||
import BigScreenConfigure from './components/BigScreenConfigure.vue'
|
||||
|
||||
const editorRef = ref(null)
|
||||
const components = ref([])
|
||||
const selectedId = ref(null)
|
||||
|
||||
// 计算选中的组件
|
||||
const selectedComponent = computed(() =>
|
||||
components.value.find(item => item.id === selectedId.value)
|
||||
)
|
||||
|
||||
// 选择组件
|
||||
const handleSelect = (component) => {
|
||||
selectedId.value = component.id
|
||||
}
|
||||
|
||||
// 更新组件列表
|
||||
const handleComponentsUpdate = (newComponents) => {
|
||||
components.value = newComponents
|
||||
}
|
||||
|
||||
// 更新组件配置
|
||||
const handleConfigUpdate = (updatedComponent) => {
|
||||
editorRef.value?.updateComponent(updatedComponent)
|
||||
}
|
||||
</script>
|
@ -1,104 +0,0 @@
|
||||
# BigScreenConfigure.vue
|
||||
<template>
|
||||
<div class="w-64 bg-white border-l border-gray-200 p-4">
|
||||
<div class="text-lg font-medium mb-4">配置面板</div>
|
||||
<template v-if="selectedComponent">
|
||||
<div class="space-y-4">
|
||||
<!-- 位置配置 -->
|
||||
<div class="space-y-2">
|
||||
<div class="text-sm font-medium text-gray-600">位置</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-1">X 坐标</div>
|
||||
<input
|
||||
type="number"
|
||||
v-model="componentConfig.x"
|
||||
@input="handleUpdate"
|
||||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-1">Y 坐标</div>
|
||||
<input
|
||||
type="number"
|
||||
v-model="componentConfig.y"
|
||||
@input="handleUpdate"
|
||||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 大小配置 -->
|
||||
<div class="space-y-2">
|
||||
<div class="text-sm font-medium text-gray-600">大小</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-1">宽度</div>
|
||||
<input
|
||||
type="number"
|
||||
v-model="componentConfig.width"
|
||||
@input="handleUpdate"
|
||||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-1">高度</div>
|
||||
<input
|
||||
type="number"
|
||||
v-model="componentConfig.height"
|
||||
@input="handleUpdate"
|
||||
class="w-full px-2 py-1 border border-gray-200 rounded text-sm focus:outline-none focus:border-blue-500"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="text-gray-400 text-center py-4">
|
||||
请选择组件进行配置
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
selectedComponent: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update'])
|
||||
|
||||
// 组件配置
|
||||
const componentConfig = ref({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
|
||||
// 监听选中组件变化
|
||||
watch(() => props.selectedComponent, (newVal) => {
|
||||
if (newVal) {
|
||||
componentConfig.value = {
|
||||
x: newVal.x,
|
||||
y: newVal.y,
|
||||
width: newVal.width,
|
||||
height: newVal.height
|
||||
}
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// 更新组件
|
||||
const handleUpdate = () => {
|
||||
if (!props.selectedComponent) return
|
||||
emit('update', {
|
||||
...props.selectedComponent,
|
||||
...componentConfig.value
|
||||
})
|
||||
}
|
||||
</script>
|
@ -1,108 +0,0 @@
|
||||
# BigScreenEditor.vue
|
||||
<template>
|
||||
<div
|
||||
class="flex-1 relative overflow-auto"
|
||||
@dragover.prevent
|
||||
@drop="handleDrop"
|
||||
:style="gridStyle"
|
||||
>
|
||||
<!-- 已添加的组件 -->
|
||||
<div
|
||||
v-for="item in components"
|
||||
:key="item.id"
|
||||
class="absolute bg-white border-2 flex items-center justify-center cursor-move transition-all"
|
||||
:class="[
|
||||
selectedId === item.id
|
||||
? 'border-blue-500 shadow-lg'
|
||||
: 'border-gray-200 hover:border-gray-300'
|
||||
]"
|
||||
:style="getPosition(item)"
|
||||
@click.stop="handleSelect(item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
gridSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
selectedId: {
|
||||
type: [Number, null],
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:components', 'select'])
|
||||
|
||||
// 编辑区网格配置
|
||||
const gridStyle = {
|
||||
backgroundSize: `${props.gridSize}px ${props.gridSize}px`,
|
||||
backgroundImage: 'linear-gradient(#f0f0f0 1px, transparent 1px), linear-gradient(90deg, #f0f0f0 1px, transparent 1px)'
|
||||
}
|
||||
|
||||
// 画布中的组件
|
||||
const components = ref([])
|
||||
|
||||
// 处理放置
|
||||
const handleDrop = (e) => {
|
||||
const type = e.dataTransfer.getData('componentType')
|
||||
const label = e.dataTransfer.getData('componentLabel')
|
||||
|
||||
// 获取放置位置
|
||||
const rect = e.target.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left
|
||||
const y = e.clientY - rect.top
|
||||
|
||||
// 对齐到网格
|
||||
const alignedX = Math.round(x / props.gridSize) * props.gridSize
|
||||
const alignedY = Math.round(y / props.gridSize) * props.gridSize
|
||||
|
||||
// 添加新组件
|
||||
const newComponents = [...components.value, {
|
||||
id: Date.now(),
|
||||
type,
|
||||
label,
|
||||
x: alignedX,
|
||||
y: alignedY,
|
||||
width: props.gridSize * 5,
|
||||
height: props.gridSize * 3
|
||||
}]
|
||||
|
||||
components.value = newComponents
|
||||
emit('update:components', newComponents)
|
||||
}
|
||||
|
||||
// 选择组件
|
||||
const handleSelect = (component) => {
|
||||
emit('select', component)
|
||||
}
|
||||
|
||||
// 获取组件位置样式
|
||||
const getPosition = (component) => {
|
||||
return {
|
||||
left: component.x + 'px',
|
||||
top: component.y + 'px',
|
||||
width: component.width + 'px',
|
||||
height: component.height + 'px'
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
updateComponent: (updatedComponent) => {
|
||||
const index = components.value.findIndex(item => item.id === updatedComponent.id)
|
||||
if (index > -1) {
|
||||
const newComponents = [...components.value]
|
||||
newComponents[index] = updatedComponent
|
||||
components.value = newComponents
|
||||
emit('update:components', newComponents)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<div class="w-64 bg-white border-r border-gray-200 p-4">
|
||||
<div class="text-lg font-medium mb-4">组件列表</div>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="item in componentList"
|
||||
:key="item.type"
|
||||
class="p-3 bg-gray-50 border border-gray-200 rounded cursor-move text-center hover:bg-gray-100 transition-colors"
|
||||
draggable="true"
|
||||
@dragstart="handleDragStart($event, item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const componentList = [
|
||||
{type: 'text', label: '文本'},
|
||||
{type: 'image', label: '图片'},
|
||||
{type: 'chart', label: '图表'},
|
||||
]
|
||||
|
||||
const handleDragStart = (e, component) => {
|
||||
e.dataTransfer.setData('componentType', component.type)
|
||||
e.dataTransfer.setData('componentLabel', component.label)
|
||||
}
|
||||
</script>
|
185
core/datacap-ui/src/views/pages/store/StoreHome.vue
Normal file
185
core/datacap-ui/src/views/pages/store/StoreHome.vue
Normal file
@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="relative min-h-screen">
|
||||
<ShadcnSpin v-if="loading" fixed/>
|
||||
<ShadcnAlert type="warning">
|
||||
{{ $t('common.plugin.systemVersion') }}
|
||||
<ShadcnTag class="text-red-400">{{ version }}</ShadcnTag>
|
||||
</ShadcnAlert>
|
||||
|
||||
<ShadcnTab v-model="activeTab" v-show="!loading" @on-change="onChange">
|
||||
<ShadcnTabItem v-for="item in metadata" :label="item.i18nFormat ? $t(item.label) : item.label" :value="item.key">
|
||||
<div class="relative">
|
||||
<ShadcnSpin v-model="item.loading" fixed/>
|
||||
|
||||
<ShadcnSpace wrap size="15">
|
||||
<ShadcnAlert v-if="item.description">
|
||||
{{ item.i18nFormat ? $t(item.description) : item.description }}
|
||||
</ShadcnAlert>
|
||||
|
||||
<ShadcnCard v-for="child in item.children" class="w-full">
|
||||
<div class="p-3 px-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<!-- Plugin -->
|
||||
<div class="flex items-center space-x-4 justify-between">
|
||||
<!-- Logo and Name -->
|
||||
<div class="flex flex-col items-center space-y-2 justify-between">
|
||||
<ShadcnAvatar class="bg-transparent border p-1.5" :src="child.logo" :alt="child.i18nFormat ? $t(child.label) : child.label"/>
|
||||
|
||||
<ShadcnText type="h6">
|
||||
{{ child.i18nFormat ? $t(child.label) : child.label }}
|
||||
</ShadcnText>
|
||||
</div>
|
||||
|
||||
<ShadcnSpace wrap :size="[20, 40]">
|
||||
<!-- Description -->
|
||||
<div class="flex flex-col space-y-2">
|
||||
<ShadcnText class="text-sm text-gray-500" type="small">
|
||||
{{ child.i18nFormat ? $t(child.description) : child.description }}
|
||||
</ShadcnText>
|
||||
|
||||
<!-- Support Version -->
|
||||
<div class="flex space-x-2 text-sm text-gray-500">
|
||||
<div class="flex items-center space-x-2">
|
||||
{{ $t('common.plugin.list.supportVersion') }} :
|
||||
</div>
|
||||
|
||||
<ShadcnTag v-for="version in child.supportVersion" type="success" :key="version">
|
||||
{{ version }}
|
||||
</ShadcnTag>
|
||||
</div>
|
||||
|
||||
<!-- Version -->
|
||||
<div class="flex space-x-2 text-sm text-gray-500">
|
||||
<div class="flex items-center space-x-2">
|
||||
{{ $t('common.plugin.version') }} :
|
||||
</div>
|
||||
|
||||
<ShadcnTag>{{ child.version }}</ShadcnTag>
|
||||
</div>
|
||||
|
||||
<!-- Other -->
|
||||
<div class="flex space-x-2 text-sm text-gray-500">
|
||||
<div class="space-x-1">
|
||||
{{ $t('common.author') }}: {{ child.author }}
|
||||
</div>
|
||||
|
||||
<ShadcnDivider type="vertical"/>
|
||||
|
||||
<div class="space-x-1">
|
||||
{{ $t('common.type') }}:
|
||||
<ShadcnTag>{{ child.type }}</ShadcnTag>
|
||||
</div>
|
||||
|
||||
<ShadcnDivider type="vertical"/>
|
||||
|
||||
<div class="space-x-1">
|
||||
{{ $t('common.releasedTime') }}:
|
||||
<ShadcnTag type="warning">{{ child.released }}</ShadcnTag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ShadcnSpace>
|
||||
</div>
|
||||
|
||||
<!-- Action -->
|
||||
<div class="flex items-center space-x-2">
|
||||
<ShadcnButton>
|
||||
{{ $t('common.install') }}
|
||||
</ShadcnButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ShadcnCard>
|
||||
</ShadcnSpace>
|
||||
</div>
|
||||
</ShadcnTabItem>
|
||||
</ShadcnTab>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCurrentInstance, onBeforeMount, ref, watch } from 'vue'
|
||||
import { useI18nHandler } from '@/i18n/I18n'
|
||||
import { PackageUtils } from '@/utils/package.ts'
|
||||
import PluginService from '@/services/plugin.ts'
|
||||
|
||||
interface MetadataItem
|
||||
{
|
||||
key: string
|
||||
label: string
|
||||
description: string
|
||||
logo: string
|
||||
type: string
|
||||
released: string
|
||||
i18nFormat: boolean
|
||||
version: string
|
||||
supportVersion: string[]
|
||||
author: string
|
||||
}
|
||||
|
||||
interface Metadata
|
||||
{
|
||||
key: string
|
||||
label: string
|
||||
description: string
|
||||
i18nFormat: boolean
|
||||
children: MetadataItem[]
|
||||
}
|
||||
|
||||
const metadataUrl = ref('https://cdn.north.devlive.org/applications/datacap/metadata.json')
|
||||
const { proxy } = getCurrentInstance()!
|
||||
const loading = ref(false)
|
||||
const metadata = ref<Metadata[]>([])
|
||||
const installPlugins = ref([])
|
||||
const activeTab = ref('plugin')
|
||||
// @ts-ignore
|
||||
const { loadingState } = useI18nHandler()
|
||||
const version = ref(PackageUtils.get('version'))
|
||||
|
||||
watch(loadingState, async (newVal) => {
|
||||
if (!newVal && !metadata.value.length) {
|
||||
await loadMetadata()
|
||||
}
|
||||
})
|
||||
|
||||
const loadMetadata = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await fetch(metadataUrl.value)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${ response.status }`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
metadata.value = data
|
||||
activeTab.value = 'plugin'
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
proxy?.$Message.error({ content: proxy?.$t('common.tip.pageNotNetwork'), showIcon: true })
|
||||
}
|
||||
else {
|
||||
proxy?.$Message.error({ content: `${ proxy?.$t('common.pageNotFoundTip') }: ${ error.message }`, showIcon: true })
|
||||
}
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onChange = (value: string) => {
|
||||
PluginService.filterByType(value)
|
||||
.then(response => {
|
||||
if (response.status) {
|
||||
installPlugins.value = response.data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (!loadingState.value) {
|
||||
loadMetadata()
|
||||
}
|
||||
})
|
||||
</script>
|
2
pom.xml
2
pom.xml
@ -16,6 +16,7 @@
|
||||
<module>core/datacap-security</module>
|
||||
<module>core/datacap-captcha</module>
|
||||
<module>core/datacap-sql</module>
|
||||
<module>core/datacap-plugin</module>
|
||||
<module>lib/datacap-http</module>
|
||||
<module>lib/datacap-logger</module>
|
||||
<module>lib/datacap-shell</module>
|
||||
@ -100,6 +101,7 @@
|
||||
<module>convert/datacap-convert-none</module>
|
||||
<module>convert/datacap-convert-csv</module>
|
||||
<module>convert/datacap-convert-xml</module>
|
||||
<module>test/datacap-test-plugin</module>
|
||||
</modules>
|
||||
|
||||
<name>datacap</name>
|
||||
|
23
test/datacap-test-plugin/pom.xml
Normal file
23
test/datacap-test-plugin/pom.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap</artifactId>
|
||||
<version>2024.4.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>datacap-test-plugin</artifactId>
|
||||
<description>DataCap - Test plugin</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,8 @@
|
||||
package io.edurt.datacap.test;
|
||||
|
||||
import io.edurt.datacap.plugin.PluginModule;
|
||||
|
||||
public class LocalModule
|
||||
extends PluginModule
|
||||
{
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.edurt.datacap.test;
|
||||
|
||||
import io.edurt.datacap.plugin.Plugin;
|
||||
|
||||
public class LocalPlugin
|
||||
implements Plugin
|
||||
{
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "Local";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String version()
|
||||
{
|
||||
return "1.0.0";
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
io.edurt.datacap.test.LocalModule
|
Loading…
Reference in New Issue
Block a user