From 296f6b2aad86032514f98b01a4db63b31696b215 Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Tue, 3 Jun 2025 14:19:03 +0800 Subject: [PATCH 1/6] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20neatlogic=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BB=93=E5=BA=93=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=95=B0=E6=8D=AE=E5=BA=93=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1432467032998096]neatlogic数据仓库支持配置第三方数据库获取数据 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1432467032998096 --- .../dao/mapper/DataBaseMapper.java | 35 +++ .../dao/mapper/DataBaseMapper.xml | 75 ++++++ .../mapper/DataWarehouseDataSourceMapper.xml | 5 + .../datawarehouse/dto/DataSourceVo.java | 10 + .../datawarehouse/dto/DatabaseVo.java | 81 ++++++ .../DatabaseConnectionFailedException.java | 39 +++ .../exceptions/DatabaseNotFoundException.java | 27 ++ .../scheduler/core/SchedulerManager.java | 2 +- .../handler/JDBCDataSourceHandler.java | 239 ++++++++++++++++++ .../changelog/2025-06-03/neatlogic_tenant.sql | 10 + .../changelog/2025-06-03/version.json | 12 + .../resources/framework/sqlscript/ddl.sql | 12 + 12 files changed, 546 insertions(+), 1 deletion(-) create mode 100644 src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java create mode 100644 src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml create mode 100644 src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java create mode 100644 src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseConnectionFailedException.java create mode 100644 src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseNotFoundException.java create mode 100644 src/main/java/neatlogic/module/framework/datawarehouse/handler/JDBCDataSourceHandler.java create mode 100644 src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/neatlogic_tenant.sql create mode 100644 src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/version.json diff --git a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java new file mode 100644 index 000000000..3024448b6 --- /dev/null +++ b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package neatlogic.framework.datawarehouse.dao.mapper; + +import neatlogic.framework.datawarehouse.dto.DatabaseVo; + +import java.util.List; + +public interface DataBaseMapper { + + DatabaseVo getDataBaseById(Long id); + + int getDataBaseCount(DatabaseVo DataBaseVo); + + List getDataBaseList(DatabaseVo DataBaseVo); + + int insertDataBase(DatabaseVo DataBaseVo); + + int deleteDataBaseById(Long id); +} diff --git a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml new file mode 100644 index 000000000..9cd5425b7 --- /dev/null +++ b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + INSERT INTO `database` (`id`, `name`, `type`, `config`) + VALUES (#{id}, #{name}, #{type}, #{configStr, typeHandler=CompressHandler}) + ON DUPLICATE KEY UPDATE + `name` = #{name}, + `type` = #{type}, + `config` = #{configStr, typeHandler=CompressHandler} + + + + DELETE FROM `database` WHERE `id` = #{value} + + \ No newline at end of file diff --git a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataWarehouseDataSourceMapper.xml b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataWarehouseDataSourceMapper.xml index c2ae1ffca..f6f45dcca 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataWarehouseDataSourceMapper.xml +++ b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataWarehouseDataSourceMapper.xml @@ -52,6 +52,7 @@ along with this program. If not, see .--> + @@ -104,6 +105,7 @@ along with this program. If not, see .--> a.module_id as moduleId, a.data_count as dataCount, a.db_type as dbType, + a.database_id as databaseId, b.id as fieldId, b.name as fieldName, b.label as fieldLabel, @@ -203,6 +205,7 @@ along with this program. If not, see .--> expire_unit = #{expireUnit}, is_active = #{isActive}, db_type = #{dbType}, + database_id = #{databaseId}, xml = #{xml,typeHandler=CompressHandler} where id = #{id} @@ -238,6 +241,7 @@ along with this program. If not, see .--> expire_unit, xml, db_type, + database_id, is_active) values (#{id}, #{name}, @@ -250,6 +254,7 @@ along with this program. If not, see .--> #{expireUnit}, #{xml,typeHandler=CompressHandler}, #{dbType}, + #{databaseId}, #{isActive}) diff --git a/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java b/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java index 085b83b26..59367fb06 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java +++ b/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java @@ -76,6 +76,8 @@ public class DataSourceVo extends BasePageVo { private List fieldList = new ArrayList<>();//需要默认值为空数组,避免空指针异常 @EntityField(name = "nfdd.datasourcevo.entityfield.name.connectionid", type = ApiParamType.LONG) private Long connectionId; + @EntityField(name = "nfdd.datasourcedatavo.entityfield.name.datasourceid", type = ApiParamType.LONG) + private Long databaseId; @JSONField(serialize = false)//数据列表 private List dataList; @EntityField(name = "nfdd.datasourcevo.entityfield.name.paramlist", type = ApiParamType.JSONARRAY) @@ -249,6 +251,14 @@ public class DataSourceVo extends BasePageVo { this.connectionId = connectionId; } + public Long getDatabaseId() { + return databaseId; + } + + public void setDatabaseId(Long databaseId) { + this.databaseId = databaseId; + } + public void setQueryTimeout(Integer queryTimeout) { this.queryTimeout = queryTimeout; } diff --git a/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java b/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java new file mode 100644 index 000000000..6146e4030 --- /dev/null +++ b/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package neatlogic.framework.datawarehouse.dto; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import neatlogic.framework.common.dto.BasePageVo; + +public class DatabaseVo extends BasePageVo { + private Long id; + private String name; + private String type; + private JSONObject config; + @JSONField(serialize = false) + private String configStr; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public JSONObject getConfig() { + if (config == null && configStr != null) { + try { + config = JSONObject.parseObject(configStr); + } catch (Exception ignored) { + + } + } + return this.config; + } + + public void setConfig(JSONObject config) { + this.config = config; + } + + public String getConfigStr() { + if (config != null) { + configStr = config.toJSONString(); + } + return configStr; + } + + public void setConfigStr(String configStr) { + this.configStr = configStr; + } +} diff --git a/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseConnectionFailedException.java b/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseConnectionFailedException.java new file mode 100644 index 000000000..eaca60a58 --- /dev/null +++ b/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseConnectionFailedException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package neatlogic.framework.datawarehouse.exceptions; + +import neatlogic.framework.exception.core.ApiRuntimeException; +import neatlogic.framework.util.$; + +public class DatabaseConnectionFailedException extends ApiRuntimeException { + + public enum Type { + CONFIG_IS_EMPTY, FILE_ID_LIST_IS_EMPTY + } + public DatabaseConnectionFailedException(Type type, String name) { + super(getMessage(type, name)); + } + + private static String getMessage(Type type, String name) { + if (type == Type.FILE_ID_LIST_IS_EMPTY) { + return $.t("nfde.databaseconnectionfailedexception.fileidlistisempty", name); + } else { + return $.t("{0}nfde.databaseconnectionfailedexception.configisempty", name); + } + } +} diff --git a/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseNotFoundException.java b/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseNotFoundException.java new file mode 100644 index 000000000..d5c412c4c --- /dev/null +++ b/src/main/java/neatlogic/framework/datawarehouse/exceptions/DatabaseNotFoundException.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package neatlogic.framework.datawarehouse.exceptions; + +import neatlogic.framework.exception.core.ApiRuntimeException; + +public class DatabaseNotFoundException extends ApiRuntimeException { + + public DatabaseNotFoundException(Long id) { + super("nfde.databasenotfoundexception.databasenotfoundexception", id); + } +} diff --git a/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java b/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java index 3c3f3e26c..47baf3fbf 100644 --- a/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java +++ b/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java @@ -262,7 +262,7 @@ public class SchedulerManager extends ModuleInitializedListenerBase { schedulerMapper.deleteJobLockByServerId(Config.SCHEDULE_SERVER_ID); UserContext.init(SystemUser.SYSTEM); for (IJob jobHandler : jobHandlerList) { - jobHandler.initJob(tenantUuid); +// jobHandler.initJob(tenantUuid); } schedulerMapper.deleteUnusedJobStatus(); } catch (Exception e) { diff --git a/src/main/java/neatlogic/module/framework/datawarehouse/handler/JDBCDataSourceHandler.java b/src/main/java/neatlogic/module/framework/datawarehouse/handler/JDBCDataSourceHandler.java new file mode 100644 index 000000000..496fbc510 --- /dev/null +++ b/src/main/java/neatlogic/module/framework/datawarehouse/handler/JDBCDataSourceHandler.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package neatlogic.module.framework.datawarehouse.handler; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import neatlogic.framework.common.util.FileUtil; +import neatlogic.framework.datawarehouse.core.DataSourceServiceHandlerBase; +import neatlogic.framework.datawarehouse.dao.mapper.DataBaseMapper; +import neatlogic.framework.datawarehouse.dao.mapper.DataWarehouseDataSourceMapper; +import neatlogic.framework.datawarehouse.dto.*; +import neatlogic.framework.datawarehouse.exceptions.DatabaseConnectionFailedException; +import neatlogic.framework.datawarehouse.exceptions.DatabaseNotFoundException; +import neatlogic.framework.datawarehouse.exceptions.ReportDataSourceSyncException; +import neatlogic.framework.exception.file.FileNotFoundException; +import neatlogic.framework.file.dao.mapper.FileMapper; +import neatlogic.framework.file.dto.FileVo; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.DocumentException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.sql.*; +import java.util.*; + +@Component +public class JDBCDataSourceHandler extends DataSourceServiceHandlerBase { + static Logger logger = LoggerFactory.getLogger(JDBCDataSourceHandler.class); + int FETCH_SIZE = 1000; + @Resource + private DataWarehouseDataSourceMapper dataSourceMapper; + @Resource + private DataBaseMapper dataBaseMapper; + + @Resource + private FileMapper fileMapper; + + @Override + public String getHandler() { + return "jdbc"; + } + + @Override + public void mySyncData(DataSourceVo dataSourceVo, DataSourceAuditVo reportDataSourceAuditVo) { + Connection conn = null; + PreparedStatement queryStatement = null; + ResultSet resultSet = null; + + try { + List selectList = getSqlFromDataSource(dataSourceVo); + conn = getConnection(dataSourceVo); + for (SelectVo select : selectList) { + String sqlText = select.getSql(); + queryStatement = conn.prepareStatement(sqlText, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + queryStatement.setFetchSize(FETCH_SIZE); + queryStatement.setFetchDirection(ResultSet.FETCH_FORWARD); + if (dataSourceVo.getQueryTimeout() != null && dataSourceVo.getQueryTimeout() > 0) { + queryStatement.setQueryTimeout(dataSourceVo.getQueryTimeout()); + } + + if (CollectionUtils.isNotEmpty(select.getParamList())) { + for (int p = 0; p < select.getParamList().size(); p++) { + if (select.getParamList().get(p) instanceof String || select.getParamList().get(p) instanceof Number) { + queryStatement.setObject(p + 1, select.getParamList().get(p)); + } else if (select.getParamList().get(p) instanceof String[]) { + // 数组参数有待处理 + queryStatement.setObject(p + 1, ((String[]) select.getParamList().get(p))[0]); + } else if (select.getParamList().get(p) instanceof Number[]) { + // 数组参数有待处理 + queryStatement.setObject(p + 1, ((Number[]) select.getParamList().get(p))[0]); + } + } + } + /* + 新增日志记录 + */ + if (logger.isInfoEnabled()) { + logger.info("REPORT RUN SQL::" + sqlText); + } + + resultSet = queryStatement.executeQuery(); + + ResultSetMetaData metaData = resultSet.getMetaData(); + Map fieldMap = new HashMap<>(); + for (int i = 1; i <= metaData.getColumnCount(); i++) { + fieldMap.put(metaData.getColumnLabel(i).toLowerCase(), i); + } + + while (resultSet.next()) { + DataSourceDataVo reportDataSourceDataVo = new DataSourceDataVo(dataSourceVo.getId()); + reportDataSourceDataVo.setExpireMinute(dataSourceVo.getExpireMinute()); + List aggregateFieldList = new ArrayList<>(); + List keyFieldList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(dataSourceVo.getParamList())) { + for (DataSourceParamVo paramVo : dataSourceVo.getParamList()) { + if (fieldMap.containsKey(paramVo.getName().toLowerCase())) { + Object v = resultSet.getObject(fieldMap.get(paramVo.getName().toLowerCase())); + Long lv = null; + try { + lv = (Long) v; + } catch (Exception ex) { + logger.error(ex.getMessage(), ex); + } + if (lv != null) { + if (paramVo.getCurrentValue() == null) { + paramVo.setCurrentValue(lv); + } else if (lv > paramVo.getCurrentValue()) { + paramVo.setCurrentValue(lv); + } + } + } + } + } + for (DataSourceFieldVo fieldVo : dataSourceVo.getFieldList()) { + if (fieldMap.containsKey(fieldVo.getName().toLowerCase())) { + Object v = resultSet.getObject(fieldMap.get(fieldVo.getName().toLowerCase())); + fieldVo.setValue(v != null ? v : "");//把所有的null值都转成空字符串 + } + reportDataSourceDataVo.addField(fieldVo); + if (StringUtils.isNotBlank(fieldVo.getAggregate())) { + aggregateFieldList.add(fieldVo); + } + if (fieldVo.getIsKey().equals(1)) { + keyFieldList.add(fieldVo); + } + } + aggregateAndInsertData(aggregateFieldList, keyFieldList, reportDataSourceDataVo, reportDataSourceAuditVo); + } + if (CollectionUtils.isNotEmpty(dataSourceVo.getParamList())) { + for (DataSourceParamVo param : dataSourceVo.getParamList()) { + dataSourceMapper.updateDataSourceParamCurrentValue(param); + } + } + } + } catch (SQLException | DocumentException | InstantiationException | IllegalAccessException | + ClassNotFoundException e) { + logger.error(e.getMessage(), e); + reportDataSourceAuditVo.setError(e.getMessage()); + throw new ReportDataSourceSyncException(dataSourceVo, e); + } finally { + try { + if (resultSet != null) { + resultSet.close(); + } + if (queryStatement != null) { + queryStatement.close(); + } + if (conn != null) { + ClassLoader classLoader = conn.getClass().getClassLoader(); + conn.close(); + if (classLoader instanceof URLClassLoader) { + ((URLClassLoader) classLoader).close(); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + + private Connection getConnection(DataSourceVo dataSourceVo) throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException { + DatabaseVo dataBaseVo = dataBaseMapper.getDataBaseById(dataSourceVo.getDatabaseId()); + if (dataBaseVo == null) { + throw new DatabaseNotFoundException(dataSourceVo.getDatabaseId()); + } + JSONObject config = dataBaseVo.getConfig(); + if (MapUtils.isNotEmpty(config)) { + String user = config.getString("user"); + String password = config.getString("password"); + String url = config.getString("url"); + String driverClassName = config.getString("driverClassName"); + Properties props = new Properties(); + if (StringUtils.isNoneBlank(user)) { + props.put("user", user); + } + if (StringUtils.isNotBlank(password)) { + props.put("password", password); + } + JSONArray fileIdList = config.getJSONArray("fileIdList"); + if (CollectionUtils.isNotEmpty(fileIdList)) { + URL[] urls = new URL[fileIdList.size()]; + for (int i = 0; i < fileIdList.size(); i++) { + Long fileId = fileIdList.getLong(i); + FileVo fileVo = fileMapper.getFileById(fileId); + if (fileVo == null) { + throw new FileNotFoundException(fileId); + } + try (InputStream is = FileUtil.getData(fileVo.getPath())) { + String fileName = fileVo.getName(); + String suffix = ".jar"; + String prefix = fileName.substring(0, fileName.length() - suffix.length()); + File file = new File(prefix + "-" + fileVo.getId() + suffix); + Path path = Paths.get(file.toURI()); + Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING); + urls[i] = file.toURI().toURL(); + }catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + URLClassLoader loader = new URLClassLoader(urls, null); + Class clazz = loader.loadClass(driverClassName); + Driver driver = ((Driver) clazz.newInstance()); + return driver.connect(url, props); + } else { + throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.FILE_ID_LIST_IS_EMPTY, dataBaseVo.getName()); + } + } else { + throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.CONFIG_IS_EMPTY, dataBaseVo.getName()); + } + } +} diff --git a/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/neatlogic_tenant.sql b/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/neatlogic_tenant.sql new file mode 100644 index 000000000..f3424461b --- /dev/null +++ b/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/neatlogic_tenant.sql @@ -0,0 +1,10 @@ +CREATE TABLE `database` ( + `id` bigint NOT NULL COMMENT '主键ID', + `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称', + `type` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '类型', + `config` text COLLATE utf8mb4_general_ci NOT NULL COMMENT '配置信息', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +ALTER TABLE `datawarehouse_datasource` + ADD COLUMN `database_id` BIGINT NULL COMMENT '数据源' AFTER `db_type`; \ No newline at end of file diff --git a/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/version.json b/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/version.json new file mode 100644 index 000000000..6ac9cae50 --- /dev/null +++ b/src/main/resources/neatlogic/resources/framework/changelog/2025-06-03/version.json @@ -0,0 +1,12 @@ +{ + "content": [ + { + "type": "功能", + "detail": [ + { + "msg": "1.数据仓库支持配置第三方数据库获取数据" + } + ] + } + ] +} diff --git a/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql b/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql index 8987dc4f7..4644fe354 100644 --- a/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql +++ b/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql @@ -112,6 +112,17 @@ CREATE TABLE IF NOT EXISTS `database_view_info` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '视图信息表'; +-- ---------------------------- +-- Table structure for database +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `database` ( + `id` bigint NOT NULL COMMENT '主键ID', + `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称', + `type` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '类型', + `config` text COLLATE utf8mb4_general_ci NOT NULL COMMENT '配置信息', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + -- ---------------------------- -- Table structure for datawarehouse_datasource -- ---------------------------- @@ -131,6 +142,7 @@ CREATE TABLE IF NOT EXISTS `datawarehouse_datasource` `data_count` int NULL DEFAULT NULL COMMENT '数据量', `expire_unit` enum ('minute','hour','day','month','year') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '过期单位', `db_type` enum ('mysql','mongodb') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'mysql' COMMENT '数据库类型', + `database_id` bigint NULL DEFAULT NULL COMMENT '数据源', `last_fire_time` timestamp(3) NULL DEFAULT NULL COMMENT '最后一次激活时间', `last_finish_time` timestamp(3) NULL DEFAULT NULL COMMENT '最后一次完成时间', `next_fire_time` timestamp(3) NULL DEFAULT NULL COMMENT '下一次激活时间', -- Gitee From 3e49ceb68996e0a4499f6d3e4a1b07fa5a98e60a Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Tue, 3 Jun 2025 14:20:42 +0800 Subject: [PATCH 2/6] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20neatlogic=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BB=93=E5=BA=93=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=95=B0=E6=8D=AE=E5=BA=93=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1432467032998096]neatlogic数据仓库支持配置第三方数据库获取数据 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1432467032998096 --- .../neatlogic/framework/scheduler/core/SchedulerManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java b/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java index 47baf3fbf..3c3f3e26c 100644 --- a/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java +++ b/src/main/java/neatlogic/framework/scheduler/core/SchedulerManager.java @@ -262,7 +262,7 @@ public class SchedulerManager extends ModuleInitializedListenerBase { schedulerMapper.deleteJobLockByServerId(Config.SCHEDULE_SERVER_ID); UserContext.init(SystemUser.SYSTEM); for (IJob jobHandler : jobHandlerList) { -// jobHandler.initJob(tenantUuid); + jobHandler.initJob(tenantUuid); } schedulerMapper.deleteUnusedJobStatus(); } catch (Exception e) { -- Gitee From e17e47249600c6212eeb59f2d8a8d97e38cb408b Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Tue, 3 Jun 2025 16:07:20 +0800 Subject: [PATCH 3/6] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20neatlogic=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BB=93=E5=BA=93=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=95=B0=E6=8D=AE=E5=BA=93=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1432467032998096]neatlogic数据仓库支持配置第三方数据库获取数据 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1432467032998096 --- .../neatlogic/framework/datawarehouse/dto/DataSourceVo.java | 2 +- .../resources/neatlogic/resources/framework/sqlscript/ddl.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java b/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java index 59367fb06..d7f9c9b31 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java +++ b/src/main/java/neatlogic/framework/datawarehouse/dto/DataSourceVo.java @@ -76,7 +76,7 @@ public class DataSourceVo extends BasePageVo { private List fieldList = new ArrayList<>();//需要默认值为空数组,避免空指针异常 @EntityField(name = "nfdd.datasourcevo.entityfield.name.connectionid", type = ApiParamType.LONG) private Long connectionId; - @EntityField(name = "nfdd.datasourcedatavo.entityfield.name.datasourceid", type = ApiParamType.LONG) + @EntityField(name = "nfdd.datasourcevo.entityfield.name.databaseid", type = ApiParamType.LONG) private Long databaseId; @JSONField(serialize = false)//数据列表 private List dataList; diff --git a/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql b/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql index 4644fe354..2881a7a9a 100644 --- a/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql +++ b/src/main/resources/neatlogic/resources/framework/sqlscript/ddl.sql @@ -142,7 +142,7 @@ CREATE TABLE IF NOT EXISTS `datawarehouse_datasource` `data_count` int NULL DEFAULT NULL COMMENT '数据量', `expire_unit` enum ('minute','hour','day','month','year') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '过期单位', `db_type` enum ('mysql','mongodb') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'mysql' COMMENT '数据库类型', - `database_id` bigint NULL DEFAULT NULL COMMENT '数据源', + `database_id` bigint NULL DEFAULT NULL COMMENT '数据库ID', `last_fire_time` timestamp(3) NULL DEFAULT NULL COMMENT '最后一次激活时间', `last_finish_time` timestamp(3) NULL DEFAULT NULL COMMENT '最后一次完成时间', `next_fire_time` timestamp(3) NULL DEFAULT NULL COMMENT '下一次激活时间', -- Gitee From 1c65ad0b94de63a58f75930f33f5a28f863f6048 Mon Sep 17 00:00:00 2001 From: "1437892690@qq.com" <1437892690@qq.com> Date: Tue, 3 Jun 2025 16:34:38 +0800 Subject: [PATCH 4/6] =?UTF-8?q?[=E5=8A=9F=E8=83=BD]=20neatlogic=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BB=93=E5=BA=93=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=95=B0=E6=8D=AE=E5=BA=93=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 关联 #[1432467032998096]neatlogic数据仓库支持配置第三方数据库获取数据 http://192.168.0.96:8090/demo/rdm.html#/story-detail/939050947543040/939050947543042/1432467032998096 --- ...ataBaseMapper.java => DatabaseMapper.java} | 2 +- ...{DataBaseMapper.xml => DatabaseMapper.xml} | 2 +- .../service/DatabaseService.java | 26 ++++ .../service/DatabaseServiceImpl.java | 115 ++++++++++++++++++ .../handler/JDBCDataSourceHandler.java | 78 ++---------- 5 files changed, 150 insertions(+), 73 deletions(-) rename src/main/java/neatlogic/framework/datawarehouse/dao/mapper/{DataBaseMapper.java => DatabaseMapper.java} (97%) rename src/main/java/neatlogic/framework/datawarehouse/dao/mapper/{DataBaseMapper.xml => DatabaseMapper.xml} (99%) create mode 100644 src/main/java/neatlogic/framework/datawarehouse/service/DatabaseService.java create mode 100644 src/main/java/neatlogic/framework/datawarehouse/service/DatabaseServiceImpl.java diff --git a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.java similarity index 97% rename from src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java rename to src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.java index 3024448b6..7ff6afe22 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.java +++ b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.java @@ -21,7 +21,7 @@ import neatlogic.framework.datawarehouse.dto.DatabaseVo; import java.util.List; -public interface DataBaseMapper { +public interface DatabaseMapper { DatabaseVo getDataBaseById(Long id); diff --git a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.xml similarity index 99% rename from src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml rename to src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.xml index 9cd5425b7..74ccc3736 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DataBaseMapper.xml +++ b/src/main/java/neatlogic/framework/datawarehouse/dao/mapper/DatabaseMapper.xml @@ -17,7 +17,7 @@ --> - + + + @@ -71,12 +72,13 @@ - INSERT INTO `database` (`id`, `name`, `type`, `config`) - VALUES (#{id}, #{name}, #{type}, #{configStr, typeHandler=CompressHandler}) + INSERT INTO `database` (`id`, `name`, `type`, `config`, `file_id_list`) + VALUES (#{id}, #{name}, #{type}, #{configStr, typeHandler=CompressHandler}, #{fileIdListStr}) ON DUPLICATE KEY UPDATE `name` = #{name}, `type` = #{type}, - `config` = #{configStr, typeHandler=CompressHandler} + `config` = #{configStr, typeHandler=CompressHandler}, + `file_id_list` = #{fileIdListStr} diff --git a/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java b/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java index 6146e4030..71a736110 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java +++ b/src/main/java/neatlogic/framework/datawarehouse/dto/DatabaseVo.java @@ -17,17 +17,25 @@ package neatlogic.framework.datawarehouse.dto; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import neatlogic.framework.common.dto.BasePageVo; +import neatlogic.framework.file.dto.FileVo; + +import java.util.List; public class DatabaseVo extends BasePageVo { private Long id; private String name; private String type; private JSONObject config; + private List fileIdList; + private List fileList; @JSONField(serialize = false) private String configStr; + @JSONField(serialize = false) + private String fileIdListStr; public Long getId() { return id; @@ -78,4 +86,38 @@ public class DatabaseVo extends BasePageVo { public void setConfigStr(String configStr) { this.configStr = configStr; } + + public List getFileIdList() { + if (fileIdList == null && fileIdListStr != null) { + try { + fileIdList = JSONArray.parseArray(fileIdListStr, Long.class); + } catch (Exception ignored) { + + } + } + return fileIdList; + } + + public void setFileIdList(List fileIdList) { + this.fileIdList = fileIdList; + } + + public List getFileList() { + return fileList; + } + + public void setFileList(List fileList) { + this.fileList = fileList; + } + + public String getFileIdListStr() { + if (fileIdListStr == null && fileIdList != null) { + fileIdListStr = JSONArray.toJSONString(fileIdList); + } + return fileIdListStr; + } + + public void setFileIdListStr(String fileIdListStr) { + this.fileIdListStr = fileIdListStr; + } } diff --git a/src/main/java/neatlogic/framework/datawarehouse/service/DatabaseServiceImpl.java b/src/main/java/neatlogic/framework/datawarehouse/service/DatabaseServiceImpl.java index 93cc6166a..d171a6c6c 100644 --- a/src/main/java/neatlogic/framework/datawarehouse/service/DatabaseServiceImpl.java +++ b/src/main/java/neatlogic/framework/datawarehouse/service/DatabaseServiceImpl.java @@ -17,7 +17,6 @@ package neatlogic.framework.datawarehouse.service; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import neatlogic.framework.common.util.FileUtil; import neatlogic.framework.datawarehouse.dao.mapper.DatabaseMapper; @@ -42,10 +41,10 @@ import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; +import java.util.List; import java.util.Properties; @Service @@ -66,50 +65,52 @@ public class DatabaseServiceImpl implements DatabaseService { if (dataBaseVo == null) { throw new DatabaseNotFoundException(databaseId); } - JSONObject config = dataBaseVo.getConfig(); - if (MapUtils.isNotEmpty(config)) { - String user = config.getString("user"); - String password = config.getString("password"); - String url = config.getString("url"); - String driverClassName = config.getString("driverClassName"); - Properties props = new Properties(); - if (StringUtils.isNoneBlank(user)) { - props.put("user", user); - } - if (StringUtils.isNotBlank(password)) { - props.put("password", password); - } - JSONArray fileIdList = config.getJSONArray("fileIdList"); - if (CollectionUtils.isNotEmpty(fileIdList)) { - URL[] urls = new URL[fileIdList.size()]; - for (int i = 0; i < fileIdList.size(); i++) { - Long fileId = fileIdList.getLong(i); - FileVo fileVo = fileMapper.getFileById(fileId); - if (fileVo == null) { - throw new FileNotFoundException(fileId); - } - try (InputStream is = FileUtil.getData(fileVo.getPath())) { - String fileName = fileVo.getName(); - String suffix = ".jar"; - String prefix = fileName.substring(0, fileName.length() - suffix.length()); - File file = new File(prefix + "-" + fileVo.getId() + suffix); + List fileIdList = dataBaseVo.getFileIdList(); + if (CollectionUtils.isNotEmpty(fileIdList)) { + URL[] urls = new URL[fileIdList.size()]; + for (int i = 0; i < fileIdList.size(); i++) { + Long fileId = fileIdList.get(i); + FileVo fileVo = fileMapper.getFileById(fileId); + if (fileVo == null) { + throw new FileNotFoundException(fileId); + } + try (InputStream is = FileUtil.getData(fileVo.getPath())) { + String fileName = fileVo.getName(); + String suffix = ".jar"; + String prefix = fileName.substring(0, fileName.length() - suffix.length()); + File file = new File(prefix + "-" + fileVo.getId() + suffix); + if (!file.exists()) { Path path = Paths.get(file.toURI()); - Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING); - urls[i] = file.toURI().toURL(); - }catch (Exception e) { - logger.error(e.getMessage(), e); - throw new RuntimeException(e); + Files.copy(is, path); } + urls[i] = file.toURI().toURL(); + }catch (Exception e) { + logger.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + JSONObject config = dataBaseVo.getConfig(); + if (MapUtils.isNotEmpty(config)) { + String user = config.getString("user"); + String password = config.getString("password"); + String url = config.getString("url"); + String driverClassName = config.getString("driverClassName"); + Properties props = new Properties(); + if (StringUtils.isNoneBlank(user)) { + props.put("user", user); + } + if (StringUtils.isNotBlank(password)) { + props.put("password", password); } URLClassLoader loader = new URLClassLoader(urls, null); Class clazz = loader.loadClass(driverClassName); Driver driver = ((Driver) clazz.newInstance()); return driver.connect(url, props); } else { - throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.FILE_ID_LIST_IS_EMPTY, dataBaseVo.getName()); + throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.CONFIG_IS_EMPTY, dataBaseVo.getName()); } } else { - throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.CONFIG_IS_EMPTY, dataBaseVo.getName()); + throw new DatabaseConnectionFailedException(DatabaseConnectionFailedException.Type.FILE_ID_LIST_IS_EMPTY, dataBaseVo.getName()); } } } -- Gitee