This commit is contained in:
limengnan 2025-06-07 09:23:18 +08:00
commit ca515c0b56
37 changed files with 4930 additions and 51 deletions

View File

@ -0,0 +1,224 @@
/*
Navicat Premium Dump SQL
Source Server : -mysql数据库
Source Server Type : MySQL
Source Server Version : 80403 (8.4.3)
Source Host : 121.37.111.42:3306
Source Schema : dataease
Target Server Type : MySQL
Target Server Version : 80403 (8.4.3)
File Encoding : 65001
Date: 30/05/2025 14:22:13
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for core_dataset_group
-- ----------------------------
DROP TABLE IF EXISTS `core_dataset_group`;
CREATE TABLE `core_dataset_group` (
`id` bigint NOT NULL COMMENT 'ID',
`app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统',
`name` varchar(128) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '名称',
`pid` bigint NULL DEFAULT NULL COMMENT '父级ID',
`level` int NULL DEFAULT 0 COMMENT '当前分组处于第几级',
`node_type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT 'node类型folder or dataset',
`type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'sql,union',
`mode` int NULL DEFAULT 0 COMMENT '连接模式0-直连1-同步(包括excel、api等数据存在de中的表)',
`info` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '关联关系树',
`create_by` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '创建人ID',
`create_time` bigint NULL DEFAULT NULL COMMENT '创建时间',
`qrtz_instance` varchar(1024) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'Quartz 实例 ID',
`sync_status` varchar(45) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '同步状态',
`update_by` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '更新人ID',
`last_update_time` bigint NULL DEFAULT 0 COMMENT '最后同步时间',
`union_sql` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '关联sql',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '数据集分组表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_dataset_table
-- ----------------------------
DROP TABLE IF EXISTS `core_dataset_table`;
CREATE TABLE `core_dataset_table` (
`id` bigint NOT NULL COMMENT 'ID',
`app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统',
`name` varchar(128) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '名称',
`table_name` varchar(128) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '物理表名',
`datasource_id` bigint NULL DEFAULT NULL COMMENT '数据源ID',
`dataset_group_id` bigint NOT NULL COMMENT '数据集ID',
`type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'db,sql,union,excel,api',
`info` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '表原始信息,表名,sql等',
`sql_variable_details` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT 'SQL参数',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = 'table数据集' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_dataset_table_field
-- ----------------------------
DROP TABLE IF EXISTS `core_dataset_table_field`;
CREATE TABLE `core_dataset_table_field` (
`id` bigint NOT NULL COMMENT 'ID',
`datasource_id` bigint NULL DEFAULT NULL COMMENT '数据源ID',
`dataset_table_id` bigint NULL DEFAULT NULL COMMENT '数据表ID',
`dataset_group_id` bigint NULL DEFAULT NULL COMMENT '数据集ID',
`chart_id` bigint NULL DEFAULT NULL COMMENT '图表ID',
`origin_name` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '原始字段名',
`name` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '字段名用于展示',
`description` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '描述',
`dataease_name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'de字段名用作唯一标识',
`field_short_name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'de字段别名',
`group_list` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '分组设置',
`other_group` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '未分组的值',
`group_type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '维度/指标标识 d:维度q:指标',
`type` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '原始字段类型',
`size` int NULL DEFAULT NULL COMMENT '字段长度允许为空默认0',
`de_type` int NOT NULL COMMENT 'dataease字段类型0-文本1-时间2-整型数值3-浮点数值4-布尔5-地理位置6-二进制7-URL',
`de_extract_type` int NOT NULL COMMENT 'de记录的原始类型',
`ext_field` int NULL DEFAULT NULL COMMENT '是否扩展字段 0原始 1复制 2计算字段...',
`checked` tinyint(1) NULL DEFAULT 1 COMMENT '是否选中',
`column_index` int NULL DEFAULT NULL COMMENT '列位置',
`last_sync_time` bigint NULL DEFAULT NULL COMMENT '同步时间',
`accuracy` int NULL DEFAULT 0 COMMENT '精度',
`date_format` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '时间字段类型',
`date_format_type` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '时间格式类型',
`params` text CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '计算字段参数',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = 'table数据集表字段' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_dataset_table_sql_log
-- ----------------------------
DROP TABLE IF EXISTS `core_dataset_table_sql_log`;
CREATE TABLE `core_dataset_table_sql_log` (
`id` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL DEFAULT '' COMMENT 'ID',
`table_id` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL DEFAULT '' COMMENT '数据集SQL节点ID',
`start_time` bigint NULL DEFAULT NULL COMMENT '开始时间',
`end_time` bigint NULL DEFAULT NULL COMMENT '结束时间',
`spend` bigint NULL DEFAULT NULL COMMENT '耗时(毫秒)',
`sql` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '详细信息',
`status` varchar(45) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = 'table数据集查询sql日志' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_datasource
-- ----------------------------
DROP TABLE IF EXISTS `core_datasource`;
CREATE TABLE `core_datasource` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统',
`name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '名称',
`description` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '描述',
`type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '类型',
`pid` bigint NULL DEFAULT NULL COMMENT '父级ID',
`edit_type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '更新方式0替换1追加',
`configuration` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '详细信息',
`create_time` bigint NOT NULL COMMENT '创建时间',
`update_time` bigint NOT NULL COMMENT '更新时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '变更人',
`create_by` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '创建人ID',
`status` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '状态',
`qrtz_instance` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '状态',
`task_status` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '任务状态',
`enable_data_fill` tinyint NULL DEFAULT 0 COMMENT '启用数据填报功能',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1915350839984336899 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '数据源表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_datasource_task
-- ----------------------------
DROP TABLE IF EXISTS `core_datasource_task`;
CREATE TABLE `core_datasource_task` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`ds_id` bigint NOT NULL COMMENT '数据源ID',
`name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '任务名称',
`update_type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '更新方式',
`start_time` bigint NULL DEFAULT NULL COMMENT '开始时间',
`sync_rate` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '执行频率0 一次性 1 cron',
`cron` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT 'cron表达式',
`simple_cron_value` bigint NULL DEFAULT NULL COMMENT '简单重复间隔',
`simple_cron_type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '简单重复类型:分、时、天',
`end_limit` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '结束限制 0 无限制 1 设定结束时间',
`end_time` bigint NULL DEFAULT NULL COMMENT '结束时间',
`create_time` bigint NULL DEFAULT NULL COMMENT '创建时间',
`last_exec_time` bigint NULL DEFAULT NULL COMMENT '上次执行时间',
`last_exec_status` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '上次执行结果',
`extra_data` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '额外数据',
`task_status` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '任务状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '数据源定时同步任务' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_datasource_task_log
-- ----------------------------
DROP TABLE IF EXISTS `core_datasource_task_log`;
CREATE TABLE `core_datasource_task_log` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`ds_id` bigint NOT NULL COMMENT '数据源ID',
`task_id` bigint NULL DEFAULT NULL COMMENT '任务ID',
`start_time` bigint NULL DEFAULT NULL COMMENT '开始时间',
`end_time` bigint NULL DEFAULT NULL COMMENT '结束时间',
`task_status` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '执行状态',
`table_name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '表名',
`info` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '错误信息',
`create_time` bigint NULL DEFAULT NULL COMMENT '创建时间',
`trigger_type` varchar(45) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '更新频率类型',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_dataset_table_task_log_ds_id`(`ds_id` ASC) USING BTREE,
INDEX `idx_dataset_table_task_log_task_id`(`task_id` ASC) USING BTREE,
INDEX `idx_dataset_table_task_log_A`(`ds_id` ASC, `table_name` ASC, `start_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1125460897473630209 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '数据源定时同步任务执行日志' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_de_engine
-- ----------------------------
DROP TABLE IF EXISTS `core_de_engine`;
CREATE TABLE `core_de_engine` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '名称',
`description` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '描述',
`type` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '类型',
`configuration` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '详细信息',
`create_time` bigint NULL DEFAULT NULL COMMENT 'Create timestamp',
`update_time` bigint NULL DEFAULT NULL COMMENT 'Update timestamp',
`create_by` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '创建人ID',
`status` varchar(45) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '数据引擎' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_driver
-- ----------------------------
DROP TABLE IF EXISTS `core_driver`;
CREATE TABLE `core_driver` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '名称',
`create_time` bigint NOT NULL COMMENT '创建时间',
`type` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '数据源类型',
`driver_class` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '驱动类',
`description` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '驱动' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for core_driver_jar
-- ----------------------------
DROP TABLE IF EXISTS `core_driver_jar`;
CREATE TABLE `core_driver_jar` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
`de_driver_id` varchar(50) CHARACTER SET utf16 COLLATE utf16_general_ci NOT NULL COMMENT '驱动主键',
`file_name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '名称',
`version` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '版本',
`driver_class` longtext CHARACTER SET utf16 COLLATE utf16_general_ci NULL COMMENT '驱动类',
`trans_name` varchar(255) CHARACTER SET utf16 COLLATE utf16_general_ci NULL DEFAULT NULL COMMENT '替换后的 jar 包名称',
`is_trans_name` tinyint(1) NULL DEFAULT NULL COMMENT '是否将上传 jar 包替换了名称1-是0-否)',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf16 COLLATE = utf16_general_ci COMMENT = '驱动详情' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.13</version>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.stdproject</groupId>
@ -14,15 +14,21 @@
<name>stdproject</name>
<description>Standard Project Backend</description>
<properties>
<spring-boot.version>3.3.0</spring-boot.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<java.version>21</java.version>
<mybatis-plus.version>3.5.3</mybatis-plus.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<jjwt.version>0.11.5</jjwt.version>
<springdoc.version>2.0.2</springdoc.version>
<calcite-core.version>1.35.18</calcite-core.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@ -45,7 +51,19 @@
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>io.gisbi</groupId>
<artifactId>sdk-bundle</artifactId>
<version>2.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/sdk-bundle-2.0.jar</systemPath>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
@ -107,18 +125,9 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version> <!-- 推荐使用最新稳定版本 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.3.1</version> <!-- 请使用你项目中统一的版本 -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version> <!-- 推荐使用最新稳定版本 --> <scope>provided</scope>
</dependency>
</dependencies>
<build>

View File

@ -13,8 +13,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
* @author StdProject
* @since 2023-12-07
*/
@SpringBootApplication
@MapperScan("com.stdproject.mapper")
@SpringBootApplication(scanBasePackages = {"com.stdproject","io.gisbi.rsa", "io.gisbi.utils", "io.gisbi.extensions"})
@MapperScan("com.stdproject.mapper,io.gisbi.rsa.dao.mapper")
@EnableCaching
@EnableAsync
@EnableTransactionManagement

View File

@ -75,4 +75,4 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
return null;
}
}
}

View File

@ -0,0 +1,22 @@
package com.stdproject.config;
import io.gisbi.utils.CommonThreadPool;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 线程池配置类
*
* @author StdProject
*/
@Configuration
public class ThreadPoolConfig {
/**
* 配置CommonThreadPool Bean
*/
@Bean
public CommonThreadPool commonThreadPool() {
return new CommonThreadPool();
}
}

View File

@ -56,13 +56,13 @@ public class AuthController {
public static class LoginRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "验证码不能为空")
private String captcha;
@NotBlank(message = "验证码Key不能为空")
private String captchaKey;
@ -83,7 +83,7 @@ public class AuthController {
public static class ChangePasswordRequest {
@NotBlank(message = "原密码不能为空")
private String oldPassword;
@NotBlank(message = "新密码不能为空")
private String newPassword;
@ -103,18 +103,18 @@ public class AuthController {
try {
// 生成验证码
CaptchaUtils.CaptchaResult captchaResult = captchaUtils.generateCaptcha();
// 生成验证码Key
String captchaKey = UUID.randomUUID().toString();
// 注意验证码应当存储在会话中或其他存储中此处省略存储步骤
// 在实际应用中可以使用Session或其他方式存储验证码
Map<String, String> result = new HashMap<>();
result.put("captchaKey", captchaKey);
result.put("captchaImage", captchaResult.getImageBase64());
result.put("code", captchaResult.getCode()); // 临时方案直接返回验证码生产环境不建议
return Result.success(result);
} catch (Exception e) {
log.error("生成验证码失败: {}", e.getMessage(), e);
@ -133,7 +133,7 @@ public class AuthController {
// 注意在实际应用中应该从会话或其他存储中获取验证码进行验证
// 此处简化处理假设验证码已通过实际应用中需要实现验证逻辑
// 如果使用了临时方案可以从前端传回验证码进行比对
// 进行身份认证
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
@ -144,16 +144,16 @@ public class AuthController {
AppUser user=appUserService.findByUsername(loginRequest.getUsername());
// 设置认证信息到安全上下文
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成JWT Token
String token = jwtUtils.generateToken(user.getUsername(),user.getId());
String token = jwtUtils.generateToken(user.getUsername(),user.getId());
Map<String, Object> result = new HashMap<>();
result.put("token", token);
result.put("userInfo", user);
return Result.success(result);
} catch (Exception e) {
log.error("用户登录失败: {}", e.getMessage(), e);
return Result.error("登录失败: " + e.getMessage());
@ -172,15 +172,15 @@ public class AuthController {
String token = request.getHeader(Constants.JWT_HEADER);
if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
token = token.substring(Constants.JWT_PREFIX.length());
// 注意在实际应用中应该实现Token失效机制
// 可以考虑使用短期Token或其他方式实现Token失效
// 此处省略Token黑名单实现
}
// 清除安全上下文
SecurityContextHolder.clearContext();
return Result.success();
} catch (Exception e) {
log.error("用户登出失败: {}", e.getMessage(), e);
@ -198,11 +198,11 @@ public class AuthController {
String token = request.getHeader(Constants.JWT_HEADER);
if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
token = token.substring(Constants.JWT_PREFIX.length());
String username = jwtUtils.getUsernameFromToken(token);
String username = jwtUtils.getUsernameFromToken(token);
AppUser userInfo = appUserService.findByUsername(username);
return Result.success(userInfo);
}
return Result.unauthorized();
} catch (Exception e) {
log.error("获取用户信息失败: {}", e.getMessage(), e);
@ -222,7 +222,7 @@ public class AuthController {
if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
token = token.substring(Constants.JWT_PREFIX.length());
String username = jwtUtils.getUsernameFromToken(token);
boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword());
if (success) {
return Result.success();
@ -230,29 +230,37 @@ public class AuthController {
return Result.error("原密码错误");
}
}
return Result.unauthorized();
} catch (Exception e) {
log.error("修改密码失败: {}", e.getMessage(), e);
return Result.error("修改密码失败");
}
}
@PostMapping("/refreshToken")
public Result<String> refreshToken(@RequestBody Map<String, String> params) {
String refreshToken = params.get("refreshToken");
if (refreshToken == null || refreshToken.trim().isEmpty()) {
return Result.error("刷新令牌不能为空");
}
// 验证refreshToken的有效性并获取用户信息
String username = jwtUtils.getUsernameFromToken(refreshToken);
if (username != null) {
AppUser user = appUserService.findByUsername(username);
// 生成新的token
return Result.success(jwtUtils.generateToken(user.getUsername(), user.getId()));
try {
String username = jwtUtils.getUsernameFromToken(refreshToken);
if (username != null && jwtUtils.validateToken(refreshToken, username)) {
AppUser user = appUserService.findByUsername(username);
String newAccessToken = jwtUtils.generateRefreshToken(user.getUsername(), user.getId());
return Result.success(newAccessToken);
} else {
return Result.error("刷新令牌已失效");
}
} catch (Exception e) {
log.error("刷新 Token 失败: {}", e.getMessage());
return Result.error("刷新 Token 失败");
}
return Result.error("无效的刷新令牌");
}
}
}

View File

@ -0,0 +1,86 @@
package com.stdproject.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.stdproject.common.OperationLog;
import com.stdproject.service.IDynamicDataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* <p>
* 动态数据管理 前端控制器
* </p>
*
* @author StdProject
* @since 2024-01-01
*/
@Tag(name = "动态数据管理", description = "提供对数据源表数据的增删改查操作")
@RestController
@RequestMapping("/api/dynamicdata")
public class DynamicDataController {
@Autowired
private IDynamicDataService dynamicDataService;
@Operation(summary = "向指定数据源的表中添加数据")
@OperationLog(type = "01", module = "动态数据管理", description = "添加表数据")
@PostMapping("addTableData")
public boolean addTableData(Long datasourceId, @RequestParam("tableData") String tableData) throws Exception {
boolean result = dynamicDataService.addTableData(
datasourceId,
tableData
);
return result;
}
@Operation(summary = "根据主键查询表数据")
@OperationLog(type = "06", module = "动态数据管理", description = "根据主键查询表数据")
@PostMapping("getTableDataByPk")
public Map<String, Object> getTableDataByPk(Long datasourceId,@RequestParam("whereJson") String whereJson) throws Exception {
Map<String, Object> result=dynamicDataService.getTableDataByPk(
datasourceId,
whereJson
);
return result;
}
@Operation(summary = "更新表数据")
@OperationLog(type = "02", module = "动态数据管理", description = "更新表数据")
@PostMapping("updateTableData")
public boolean updateTableData(Long datasourceId, @RequestParam("tableData") String tableData) throws Exception {
boolean result = dynamicDataService.updateTableData(
datasourceId,
tableData
);
return result;
}
@Operation(summary = "删除表数据")
@OperationLog(type = "03", module = "动态数据管理", description = "删除表数据")
@PostMapping("deleteTableData")
public boolean deleteTableData(Long datasourceId, @RequestParam("whereJson") String whereJson) throws Exception {
boolean result = dynamicDataService.deleteTableData(
datasourceId,
whereJson
);
return result;
}
@Operation(summary = "分页查询表数据")
@OperationLog(type = "06", module = "动态数据管理", description = "分页查询表数据")
@PostMapping("queryTableDataPaged")
public Page<Map<String, Object>> queryTableDataPaged(Long datasourceId, @RequestParam("queryJson") String queryJson) throws Exception {
Page<Map<String, Object>> result = dynamicDataService.queryTableDataPaged(
datasourceId,
queryJson
);
return result;
}
}

View File

@ -0,0 +1,62 @@
package com.stdproject.controller;
import com.stdproject.entity.CoreDeEngine;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data
public class EngineRequest {
private final String REG_WITH_SQL_FRAGMENT = "((?i)WITH[\\s\\S]+(?i)AS?\\s*\\([\\s\\S]+\\))\\s*(?i)SELECT";
private Pattern WITH_SQL_FRAGMENT = Pattern.compile("((?i)WITH[\\s\\S]+(?i)AS?\\s*\\([\\s\\S]+\\))\\s*(?i)SELECT");
protected String query;
protected String table;
protected CoreDeEngine engine;
private Integer pageSize;
private Integer page;
private Integer realSize;
private Integer fetchSize = 10000;
private boolean pageable = false;
private boolean previewData = false;
private boolean totalPageFlag;
public EngineRequest() {
}
public String getQuery() {
return this.rebuildSqlWithFragment(this.query);
}
public void setQuery(String query) {
this.query = query;
}
private String rebuildSqlWithFragment(String sql) {
if (!sql.toLowerCase().startsWith("with")) {
Matcher matcher = this.WITH_SQL_FRAGMENT.matcher(sql);
if (matcher.find()) {
String withFragment = matcher.group();
if (!StringUtils.isEmpty(withFragment)) {
if (withFragment.length() > 6) {
int lastSelectIndex = withFragment.length() - 6;
sql = sql.replace(withFragment, withFragment.substring(lastSelectIndex));
withFragment = withFragment.substring(0, lastSelectIndex);
}
sql = withFragment + " " + sql;
sql = sql.replaceAll(" {2,}", " ");
}
}
}
return sql;
}
public String getREG_WITH_SQL_FRAGMENT() {
this.getClass();
return "((?i)WITH[\\s\\S]+(?i)AS?\\s*\\([\\s\\S]+\\))\\s*(?i)SELECT";
}
}

View File

@ -0,0 +1,250 @@
package com.stdproject.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* <p>
* 数据源表
* </p>
*
* @Author bi-coder
* @since 2024-07-09
*/
@TableName("core_datasource")
public class CoreDatasource implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 应用ID
*/
private String appId;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 类型
*/
private String type;
/**
* 父级ID
*/
private Long pid;
/**
* 更新方式0替换1追加
*/
private String editType;
/**
* 详细信息
*/
private String configuration;
/**
* 创建时间
*/
private Long createTime;
/**
* 更新时间
*/
private Long updateTime;
/**
* 变更人
*/
private Long updateBy;
/**
* 创建人ID
*/
private String createBy;
/**
* 状态
*/
private String status;
/**
* 状态
*/
private String qrtzInstance;
/**
* 任务状态
*/
private String taskStatus;
/**
* 开启数据填报
*/
private Boolean enableDataFill;
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getEditType() {
return editType;
}
public void setEditType(String editType) {
this.editType = editType;
}
public String getConfiguration() {
return configuration;
}
public void setConfiguration(String configuration) {
this.configuration = configuration;
}
public Long getCreateTime() {
return createTime;
}
public void setCreateTime(Long createTime) {
this.createTime = createTime;
}
public Long getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Long updateTime) {
this.updateTime = updateTime;
}
public Long getUpdateBy() {
return updateBy;
}
public void setUpdateBy(Long updateBy) {
this.updateBy = updateBy;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getQrtzInstance() {
return qrtzInstance;
}
public void setQrtzInstance(String qrtzInstance) {
this.qrtzInstance = qrtzInstance;
}
public String getTaskStatus() {
return taskStatus;
}
public void setTaskStatus(String taskStatus) {
this.taskStatus = taskStatus;
}
public Boolean getEnableDataFill() {
return enableDataFill;
}
public void setEnableDataFill(Boolean enableDataFill) {
this.enableDataFill = enableDataFill;
}
@Override
public String toString() {
return "CoreDatasource{" +
"id = " + id +
", appId = " + appId +
", name = " + name +
", description = " + description +
", type = " + type +
", pid = " + pid +
", editType = " + editType +
", configuration = " + configuration +
", createTime = " + createTime +
", updateTime = " + updateTime +
", updateBy = " + updateBy +
", createBy = " + createBy +
", status = " + status +
", qrtzInstance = " + qrtzInstance +
", taskStatus = " + taskStatus +
", enableDataFill = " + enableDataFill +
"}";
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
}

View File

@ -0,0 +1,154 @@
package com.stdproject.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @Author bi-coder
* @since 2023-04-18
*/
@TableName("core_de_engine")
public class CoreDeEngine implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 类型
*/
private String type;
/**
* 详细信息
*/
private String configuration;
/**
* Create timestamp
*/
private Long createTime;
/**
* Update timestamp
*/
private Long updateTime;
/**
* 创建人ID
*/
private String createBy;
/**
* 状态
*/
private String status;
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getConfiguration() {
return configuration;
}
public void setConfiguration(String configuration) {
this.configuration = configuration;
}
public Long getCreateTime() {
return createTime;
}
public void setCreateTime(Long createTime) {
this.createTime = createTime;
}
public Long getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Long updateTime) {
this.updateTime = updateTime;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "CoreDeEngine{" +
"id = " + id +
", name = " + name +
", description = " + description +
", type = " + type +
", configuration = " + configuration +
", createTime = " + createTime +
", updateTime = " + updateTime +
", createBy = " + createBy +
", status = " + status +
"}";
}
}

View File

@ -0,0 +1,112 @@
package com.stdproject.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* <p>
* 驱动
* </p>
*
* @Author bi-coder
* @since 2023-04-18
*/
@TableName("core_driver")
public class CoreDriver implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 名称
*/
private String name;
/**
* 创健时间
*/
private Long createTime;
/**
* 数据源类型
*/
private String type;
/**
* 驱动类
*/
private String driverClass;
/**
* 描述
*/
private String description;
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 Long getCreateTime() {
return createTime;
}
public void setCreateTime(Long createTime) {
this.createTime = createTime;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDriverClass() {
return driverClass;
}
public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "CoreDriver{" +
"id = " + id +
", name = " + name +
", createTime = " + createTime +
", type = " + type +
", driverClass = " + driverClass +
", description = " + description +
"}";
}
}

View File

@ -0,0 +1,120 @@
package com.stdproject.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* <p>
* 驱动详情
* </p>
*
* @Author bi-coder
* @since 2023-04-17
*/
@TableName("core_driver_jar")
public class CoreDriverJar implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 驱动主键
*/
private String deDriverId;
/**
* 名称
*/
private String fileName;
/**
* 版本
*/
private String version;
/**
* 驱动类
*/
private String driverClass;
private String transName;
private Boolean isTransName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDeDriverId() {
return deDriverId;
}
public void setDeDriverId(String deDriverId) {
this.deDriverId = deDriverId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getDriverClass() {
return driverClass;
}
public void setDriverClass(String driverClass) {
this.driverClass = driverClass;
}
public String getTransName() {
return transName;
}
public void setTransName(String transName) {
this.transName = transName;
}
public Boolean getIsTransName() {
return isTransName;
}
public void setIsTransName(Boolean isTransName) {
this.isTransName = isTransName;
}
@Override
public String toString() {
return "CoreDriverJar{" +
"id = " + id +
", deDriverId = " + deDriverId +
", fileName = " + fileName +
", version = " + version +
", driverClass = " + driverClass +
", transName = " + transName +
", isTransName = " + isTransName +
"}";
}
}

View File

@ -0,0 +1,18 @@
package com.stdproject.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.stdproject.entity.CoreDatasource;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 数据源表 Mapper 接口
* </p>
*
* @Author bi-coder
* @since 2024-07-09
*/
@Mapper
public interface CoreDatasourceMapper extends BaseMapper<CoreDatasource> {
}

View File

@ -0,0 +1,19 @@
package com.stdproject.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.stdproject.entity.CoreDeEngine;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @Author bi-coder
* @since 2023-04-18
*/
@Mapper
public interface CoreDeEngineMapper extends BaseMapper<CoreDeEngine> {
}

View File

@ -0,0 +1,129 @@
package com.stdproject.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.Map;
/**
* 动态数据服务接口
* 提供对数据源表数据的增删改查操作
*/
public interface IDynamicDataService {
/**
* 向指定数据源的表中添加数据
*
* @param datasourceId 数据源ID
* @param tableData 表数据JSON字符串格式
* {
* "tableName": "user",
* "data": [
* {
* "fieldName": "id",
* "fieldType": "varchar",
* "IsPrimaryKey": true,
* "fieldValue": "0001"
* },
* {
* "fieldName": "name",
* "fieldType": "varchar",
* "fieldValue": "张三"
* }
* ]
* }
* @return 是否添加成功
* @throws Exception 操作异常
*/
boolean addTableData(Long datasourceId, String tableData) throws Exception;
/**
* 根据主键查询表数据
*
* @param datasourceId 数据源ID
* @param condition 查询条件JSON字符串格式
* {
* "tableName": "user",
* "key": [
* {
* "fieldName": "id",
* "fieldValue": "0001"
* }
* ]
* }
* @return 查询到的数据Map如果没有找到则返回null
* @throws Exception 操作异常
*/
Map<String, Object> getTableDataByPk(Long datasourceId, String condition) throws Exception;
/**
* 更新表数据
*
* @param datasourceId 数据源ID
* @param tableData 更新数据JSON字符串格式
* {
* "tableName": "user",
* "key": [
* {
* "fieldName": "id",
* "fieldValue": "0001"
* }
* ],
* "data": [
* {
* "fieldName": "name",
* "fieldType": "varchar",
* "fieldValue": "李四"
* }
* ]
* }
* @return 是否更新成功
* @throws Exception 操作异常
*/
boolean updateTableData(Long datasourceId, String tableData) throws Exception;
/**
* 删除表数据
*
* @param datasourceId 数据源ID
* @param condition 删除条件JSON字符串格式
* {
* "tableName": "user",
* "key": [
* {
* "fieldName": "id",
* "fieldValue": "0001"
* }
* ]
* }
* @return 是否删除成功
* @throws Exception 操作异常
*/
boolean deleteTableData(Long datasourceId, String condition) throws Exception;
/**
* 分页查询表数据
*
* @param datasourceId 数据源ID
* @param condition 查询条件JSON字符串格式
* {
* "tableName": "user",
* "pageNum": 1,
* "pageSize": 10,
* "conditions": [
* {
* "field": "name",
* "operator": "like",
* "value": ""
* },
* {
* "field": "age",
* "operator": ">",
* "value": 18
* }
* ]
* }
* @return 分页查询结果
* @throws Exception 操作异常
*/
Page<Map<String, Object>> queryTableDataPaged(Long datasourceId, String condition) throws Exception;
}

View File

@ -22,6 +22,7 @@ import java.time.LocalDateTime;
* @author StdProject
* @since 2023-12-07
*/
@Service
public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> implements IAppUserService {

View File

@ -0,0 +1,428 @@
package com.stdproject.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.stdproject.common.BusinessException;
import com.stdproject.entity.CoreDatasource;
import com.stdproject.mapper.CoreDatasourceMapper;
import com.stdproject.service.IDynamicDataService;
import io.gisbi.extensions.datasource.dto.DatasourceRequest;
import io.gisbi.extensions.datasource.dto.DatasourceSchemaDTO;
import io.gisbi.extensions.datasource.dto.TableField;
import io.gisbi.extensions.datasource.factory.ProviderFactory;
import io.gisbi.extensions.datasource.provider.Provider;
import io.gisbi.utils.BeanUtils;
import io.gisbi.utils.IDUtils;
import io.gisbi.utils.JsonUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.stdproject.utils.EncryptUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service
public class DynamicDataServiceImpl implements IDynamicDataService {
@Resource
private CoreDatasourceMapper coreDatasourceMapper;
@Override
public boolean addTableData(Long datasourceId, String tableData) throws Exception {
// 根据数据源 id 查询数据源信息调用通用数据源执行器
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasourceId);
coreDatasource.setConfiguration(String.valueOf(EncryptUtils.aesDecrypt(coreDatasource.getConfiguration())));
if (coreDatasource == null) {
BusinessException.throwException("数据源不存在");
}
// 解析 tableData JSON 字符串 "{ \"tableName\": \"user\", \"data\": [ { \"fieldName\": \"id\", \"fieldType\": \"varchar\", \"IsPrimaryKey\": true, \"fieldValue\": \"0001\" }, { \"fieldName\": \"name\", \"fieldType\": \"varchar\", \"fieldValue\": \"张三\" } ] }";
Map<String, Object> dataMap = JsonUtil.parseObject(tableData, Map.class);
String tableName = (String) dataMap.get("tableName");
List<Map<String, Object>> fieldList = (List<Map<String, Object>>) dataMap.get("data");
if (fieldList == null || fieldList.isEmpty()) {
BusinessException.throwException("没有可插入的数据字段");
}
// 构建插入语句
StringBuilder columns = new StringBuilder();
StringBuilder values = new StringBuilder();
for (int i = 0; i < fieldList.size(); i++) {
Map<String, Object> field = fieldList.get(i);
String fieldName = (String) field.get("fieldName");
Object fieldValue = field.get("fieldValue");
boolean isPrimaryKey = field.get("IsPrimaryKey") != null && (boolean) field.get("IsPrimaryKey");
if (isPrimaryKey) {
if (fieldValue == null) {fieldValue= IDUtils.snowID();}
}
if (i > 0) {
columns.append(", ");
values.append(", ");
}
columns.append(fieldName);
if (fieldValue instanceof String) {
values.append("'").append(fieldValue).append("'");
} else {
values.append(fieldValue);
}
}
String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", tableName, columns.toString(), values.toString());
// 调用执行器向数据表中插入 tableData 数据
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
Provider provider = ProviderFactory.getProvider(coreDatasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(sql);
datasourceRequest.setDsList(Map.of(datasourceSchemaDTO.getId(), datasourceSchemaDTO));
log.debug("执行插入数据的SQL: {}", sql);
// 执行插入操作
int result= provider.executeUpdate(datasourceRequest);
if (result==1) {
return true;
// process result set
} else {
return false;
}
}
@Override
public Map<String, Object> getTableDataByPk(Long datasourceId, String condtion) throws Exception {
// 获取数据源信息
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasourceId);
if (coreDatasource == null) {
BusinessException.throwException("数据源不存在");
}
// 解析 JSON 数据
//condtion={ \"tableName\": \"user\", key:[{ \"fieldName\": \"id\",\"fieldValue\": \"0001\"]
Map<String, Object> dataMap = JsonUtil.parseObject(condtion, Map.class);
String tableName = (String) dataMap.get("tableName");
// 参数校验
if (StringUtils.isBlank(tableName)) {
BusinessException.throwException("表名不能为空");
}
List<Map<String, Object>> keyFields = (List<Map<String, Object>>) dataMap.get("key");
if (CollectionUtils.isEmpty(keyFields)) {
BusinessException.throwException("主键字段或值不能为空");
}
String whereClause = buildWhereCondition(keyFields);
String sql = String.format("SELECT * FROM %s WHERE %s", tableName, whereClause);
// 执行查询操作
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
Provider provider = ProviderFactory.getProvider(coreDatasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(sql);
datasourceRequest.setDsList(Map.of(datasourceSchemaDTO.getId(), datasourceSchemaDTO));
log.debug("执行查询数据的SQL: {}", sql);
// 获取查询结果
Map<String, Object> data = provider.fetchResultField(datasourceRequest);
// 处理查询结果
List<String[]> dataList = (List<String[]>) data.get("data");
List<TableField> fields = (List<TableField>) data.get("fields");
if (CollectionUtils.isEmpty(dataList) || dataList.size() == 0) {
return null;
}
// 将结果转换为 Map 格式
String[] row = dataList.get(0);
Map<String, Object> resultMap = new LinkedHashMap<>();
for (int i = 0; i < fields.size(); i++) {
TableField field = fields.get(i);
String fieldName = field.getOriginName();
resultMap.put(fieldName, row[i]);
}
return resultMap;
}
/**
* 构建 WHERE 条件字符串用于多字段主键查询/更新/删除操作
*
* @param keyFields 主键字段列表格式如{ "fieldName": "id", "fieldValue": "0001" }
* @return SQL WHERE 子句字符串
*/
private String buildWhereCondition(List<Map<String, Object>> keyFields) {
StringBuilder whereClause = new StringBuilder();
for (int i = 0; i < keyFields.size(); i++) {
Map<String, Object> keyField = keyFields.get(i);
String fieldName = (String) keyField.get("fieldName");
Object fieldValue = keyField.get("fieldValue");
if (i > 0) {
whereClause.append(" AND ");
}
if (fieldValue == null) {
whereClause.append(fieldName).append(" IS NULL");
} else if (fieldValue instanceof String) {
whereClause.append(String.format("%s = '%s'", fieldName, fieldValue));
} else {
whereClause.append(String.format("%s = %s", fieldName, fieldValue));
}
}
return whereClause.toString();
}
@Override
public boolean updateTableData(Long datasourceId, String tableData) throws Exception {
// 获取数据源信息
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasourceId);
if (coreDatasource == null) {
BusinessException.throwException("数据源不存在");
}
//String tableDataJson = "{ \"tableName\": \"user\", key:[{ \"fieldName\": \"id\",\"fieldValue\": \"0001\"], \"data\": [ { \"fieldName\": \"name\", \"fieldType\": \"varchar\", \"fieldValue\": \"李四\" } ] }";
// 解析 JSON 数据
Map<String, Object> dataMap = JsonUtil.parseObject(tableData, Map.class);
String tableName = (String) dataMap.get("tableName");
if (StringUtils.isBlank(tableName)) {
BusinessException.throwException("表名不能为空");
}
List<Map<String, Object>> keyFields = (List<Map<String, Object>>) dataMap.get("key");
if (CollectionUtils.isEmpty(keyFields)) {
BusinessException.throwException("主键字段或值不能为空");
}
List<Map<String, Object>> fieldList = (List<Map<String, Object>>) dataMap.get("data");
if (fieldList == null || fieldList.isEmpty()) {
BusinessException.throwException("没有可更新的数据字段");
}
// 构建 UPDATE 语句
StringBuilder setClause = new StringBuilder();
for (int i = 0; i < fieldList.size(); i++) {
Map<String, Object> field = fieldList.get(i);
String fieldName = (String) field.get("fieldName");
Object fieldValue = field.get("fieldValue");
if (i > 0) {
setClause.append(", ");
}
if (fieldValue instanceof String) {
setClause.append(String.format("%s = '%s'", fieldName, fieldValue));
} else {
setClause.append(String.format("%s = %s", fieldName, fieldValue));
}
}
String whereClause = buildWhereCondition(keyFields);
String sql = String.format("UPDATE %s SET %s WHERE %s", tableName, setClause, whereClause);
// 调用执行器执行 SQL
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
Provider provider = ProviderFactory.getProvider(coreDatasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(sql);
datasourceRequest.setDsList(Map.of(datasourceSchemaDTO.getId(), datasourceSchemaDTO));
log.debug("执行更新数据的SQL: {}", sql);
// 执行更新操作
int result= provider.executeUpdate(datasourceRequest);
if (result==1) {
return true;
// process result set
} else {
return false;
}
}
@Override
public boolean deleteTableData(Long datasourceId, String condtion) throws Exception {
// 获取数据源信息
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasourceId);
if (coreDatasource == null) {
BusinessException.throwException("数据源不存在"); }
// 解析 JSON 数据
//String tableDataJson = "{ \"tableName\": \"user\", key:[{ \"fieldName\": \"id\",\"fieldValue\": \"0001\"] }";
Map<String, Object> dataMap = JsonUtil.parseObject(condtion, Map.class);
String tableName = (String) dataMap.get("tableName");
if (StringUtils.isBlank(tableName)) {
BusinessException.throwException("表名不能为空");
}
List<Map<String, Object>> keyFields = (List<Map<String, Object>>) dataMap.get("key");
if (CollectionUtils.isEmpty(keyFields)) {
BusinessException.throwException("主键字段或值不能为空");
}
String whereClause = buildWhereCondition(keyFields);
String sql = String.format("DELETE FROM %s WHERE %s", tableName, whereClause);
// 调用执行器执行 SQL
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
Provider provider = ProviderFactory.getProvider(coreDatasource.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(sql);
datasourceRequest.setDsList(Map.of(datasourceSchemaDTO.getId(), datasourceSchemaDTO));
log.debug("执行删除数据的SQL: {}", sql);
// 执行删除操作
int result= provider.executeUpdate(datasourceRequest);
if (result==1) {
return true;
// process result set
} else {
return false;
}
}
@Override
public Page<Map<String, Object>> queryTableDataPaged(Long datasourceId, String condition) throws Exception {
// 获取数据源信息
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasourceId);
if (coreDatasource == null) {
BusinessException.throwException("数据源不存在");
}
// 解析 condition JSON 数据
Map<String, Object> dataMap = JsonUtil.parseObject(condition, Map.class);
String tableName = (String) dataMap.get("tableName");
List<Map<String, Object>> conditionList = (List<Map<String, Object>>) dataMap.get("conditions");
Integer pageNum = (Integer) dataMap.getOrDefault("pageNum", 1);
Integer pageSize = (Integer) dataMap.getOrDefault("pageSize", 10);
if (StringUtils.isBlank(tableName)) {
BusinessException.throwException("表名不能为空");
}
// 构建 WHERE 条件子句
StringBuilder whereClause = new StringBuilder();
if (conditionList != null && !conditionList.isEmpty()) {
whereClause.append(" WHERE ");
for (int i = 0; i < conditionList.size(); i++) {
Map<String, Object> cond = conditionList.get(i);
String field = (String) cond.get("field");
String operator = ((String) cond.get("operator")).toLowerCase();
Object value = cond.get("value");
if (i > 0) {
whereClause.append(" AND ");
}
switch (operator) {
case "like":
whereClause.append(String.format("%s LIKE '%%%s%%'", field, value));
break;
case "=":
appendValue(whereClause, field, value, "=");
break;
case "<":
appendValue(whereClause, field, value, "<");
break;
case ">":
appendValue(whereClause, field, value, ">");
break;
case "<=":
appendValue(whereClause, field, value, "<=");
break;
case ">=":
appendValue(whereClause, field, value, ">=");
break;
case "!=":
case "<>":
appendValue(whereClause, field, value, "<>");
break;
case "in":
if (!(value instanceof List<?>)) {
BusinessException.throwException("IN 操作符要求值为列表类型");
}
List<?> values = (List<?>) value;
String inValues = values.stream()
.map(v -> v instanceof String ? "'" + v + "'" : v.toString())
.collect(Collectors.joining(", "));
whereClause.append(String.format("%s IN (%s)", field, inValues));
break;
default:
BusinessException.throwException("不支持的操作符: " + operator);
}
}
}
// 构建基础 SQL
String baseSql = String.format("SELECT * FROM %s%s", tableName, whereClause);
String dbType = coreDatasource.getType().toLowerCase();
String pagedSql = buildPagedSQL(baseSql, dbType, pageNum, pageSize);
String countSql = String.format("SELECT COUNT(*) FROM %s%s", tableName, whereClause);
DatasourceSchemaDTO schemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(schemaDTO, coreDatasource);
Provider provider = ProviderFactory.getProvider(coreDatasource.getType());
DatasourceRequest request = new DatasourceRequest();
request.setDsList(Map.of(schemaDTO.getId(), schemaDTO));
// 查询分页数据
request.setQuery(pagedSql);
Map<String, Object> result = provider.fetchResultField(request);
List<String[]> dataList = (List<String[]>) result.get("data");
List<TableField> fields = (List<TableField>) result.get("fields");
// 查询总记录数
request.setQuery(countSql);
Map<String, Object> countResult = provider.fetchResultField(request);
long total = Long.parseLong(((List<String[]>) countResult.get("data")).get(0)[0]);
// 将数据封装为 Map 形式
List<Map<String, Object>> records = new ArrayList<>();
if (!CollectionUtils.isEmpty(dataList)) {
for (String[] row : dataList) {
Map<String, Object> rowMap = new LinkedHashMap<>();
for (int i = 0; i < fields.size() && i < row.length; i++) {
String fieldName = fields.get(i).getOriginName();
String fieldValue = row[i];
rowMap.put(fieldName, fieldValue);
}
records.add(rowMap);
}
}
// 返回分页结果
Page<Map<String, Object>> page = new Page<>();
page.setCurrent(pageNum);
page.setSize(pageSize);
page.setTotal(total);
page.setRecords(records);
return page;
}
private void appendValue(StringBuilder sb, String field, Object value, String op) {
if (value instanceof String) {
sb.append(String.format("%s %s '%s'", field, op, value));
} else {
sb.append(String.format("%s %s %s", field, op, value));
}
}
private String buildPagedSQL(String baseSql, String dbType, int pageNum, int pageSize) {
int offset = (pageNum - 1) * pageSize;
switch (dbType) {
case "mysql":
case "mariadb":
return String.format("%s LIMIT %d OFFSET %d", baseSql, pageSize, offset);
case "postgresql":
return String.format("%s LIMIT %d OFFSET %d", baseSql, pageSize, offset);
case "oracle":
int start = offset + 1;
int end = offset + pageSize;
return String.format("SELECT * FROM (SELECT ROWNUM rn, t.* FROM (%s) t WHERE ROWNUM <= %d) WHERE rn >= %d", baseSql, end, start);
case "sqlserver":
return String.format("%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY", baseSql, offset, pageSize);
default:
// 默认使用 MySQL 方式
return String.format("%s LIMIT %d OFFSET %d", baseSql, pageSize, offset);
}
}
}

View File

@ -0,0 +1,197 @@
package com.stdproject.service.manage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.stdproject.entity.CoreDatasource;
import com.stdproject.entity.CoreDeEngine;
import com.stdproject.mapper.CoreDatasourceMapper;
import com.stdproject.mapper.CoreDeEngineMapper;
import com.stdproject.service.type.H2;
import com.stdproject.service.type.Mysql;
import io.gisbi.exception.DEException;
import io.gisbi.extensions.datasource.dto.DatasourceDTO;
import io.gisbi.extensions.datasource.dto.DatasourceRequest;
import io.gisbi.extensions.datasource.factory.ProviderFactory;
import io.gisbi.result.ResultMessage;
import io.gisbi.utils.BeanUtils;
import io.gisbi.utils.JsonUtil;
import io.gisbi.utils.ModelUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
@Transactional(rollbackFor = Exception.class)
public class EngineManage {
@Resource
private Environment env;
@Resource
private CoreDeEngineMapper deEngineMapper;
@Resource
private CoreDatasourceMapper datasourceMapper;
@Value("${gisbi.path.engine:jdbc:h2:/opt/gisbi/desktop_data;AUTO_SERVER=TRUE;AUTO_RECONNECT=TRUE;MODE=MySQL;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DATABASE_TO_UPPER=FALSE}")
private String engineUrl;
public CoreDeEngine info() throws DEException {
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
if (CollectionUtils.isEmpty(deEngines)) {
DEException.throwException("未完整设置数据引擎");
}
return deEngines.get(0);
}
public CoreDatasource getDeEngine() {
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
if (CollectionUtils.isEmpty(deEngines)) {
DEException.throwException("未完整设置数据引擎");
}
CoreDatasource coreDatasource = new CoreDatasource();
BeanUtils.copyBean(coreDatasource, deEngines.get(0));
return coreDatasource;
}
public CoreDatasource deEngine() {
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
CoreDatasource coreDatasource = new CoreDatasource();
if (CollectionUtils.isEmpty(deEngines)) {
return null;
}
BeanUtils.copyBean(coreDatasource, deEngines.get(0));
return coreDatasource;
}
public void validate(CoreDeEngine engine) throws Exception {
if (StringUtils.isEmpty(engine.getType()) || StringUtils.isEmpty(engine.getConfiguration())) {
throw new Exception("未完整设置数据引擎");
}
try {
DatasourceRequest datasourceRequest = new DatasourceRequest();
DatasourceDTO datasource = new DatasourceDTO();
BeanUtils.copyBean(datasource, engine);
datasourceRequest.setDatasource(datasource);
ProviderFactory.getProvider(engine.getType()).checkStatus(datasourceRequest);
} catch (Exception e) {
DEException.throwException("校验失败:" + e.getMessage());
}
}
public ResultMessage save(CoreDeEngine engine) throws Exception {
if (engine.getId() == null) {
deEngineMapper.insert(engine);
} else {
deEngineMapper.updateById(engine);
}
return ResultMessage.success(engine);
}
public void initSimpleEngine() throws Exception {
initLocalDataSource();
QueryWrapper<CoreDeEngine> queryWrapper = new QueryWrapper<>();
if (ModelUtils.isDesktop()) {
queryWrapper.eq("type", engineType.h2.name());
} else {
queryWrapper.eq("type", engineType.mysql.name());
}
List<CoreDeEngine> deEngines = deEngineMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(deEngines)) {
return;
}
CoreDeEngine engine = new CoreDeEngine();
if (ModelUtils.isDesktop()) {
engine.setType(engineType.h2.name());
H2 h2 = new H2();
h2.setJdbc(engineUrl);
h2.setDataBase("PUBLIC");
h2.setUsername(env.getProperty("spring.datasource.username"));
h2.setPassword(env.getProperty("spring.datasource.password"));
engine.setConfiguration(JsonUtil.toJSONString(h2).toString());
} else {
engine.setType(engineType.mysql.name());
Mysql mysqlConfiguration = new Mysql();
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)");
Matcher matcher = WITH_SQL_FRAGMENT.matcher(env.getProperty("spring.datasource.url"));
if (!matcher.find()) {
return;
}
mysqlConfiguration.setHost(matcher.group(1));
mysqlConfiguration.setPort(Integer.valueOf(matcher.group(2)));
String[] databasePrams = matcher.group(3).split("\\?");
mysqlConfiguration.setDataBase(databasePrams[0]);
if (databasePrams.length == 2) {
mysqlConfiguration.setExtraParams(databasePrams[1]);
}
mysqlConfiguration.setUsername(env.getProperty("spring.datasource.username"));
mysqlConfiguration.setPassword(env.getProperty("spring.datasource.password"));
engine.setConfiguration(JsonUtil.toJSONString(mysqlConfiguration).toString());
}
engine.setName("默认引擎");
engine.setDescription("默认引擎");
deEngineMapper.insert(engine);
}
public enum engineType {
mysql("Mysql"),
h2("h2");
private String alias;
private engineType(String alias) {
this.alias = alias;
}
public String getAlias() {
return alias;
}
}
public void initLocalDataSource() {
QueryWrapper<CoreDatasource> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", 985188400292302848L);
queryWrapper.ne("create_time", 1715053684176L);
if (!datasourceMapper.exists(queryWrapper) && !ModelUtils.isDesktop()) {
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)\\?(.*)");
Matcher matcher = WITH_SQL_FRAGMENT.matcher(env.getProperty("spring.datasource.url"));
if (!matcher.find()) {
return;
}
Map configuration = new HashMap<>();
configuration.put("dataBase", matcher.group(3));
configuration.put("username", env.getProperty("spring.datasource.username"));
configuration.put("password", env.getProperty("spring.datasource.password"));
configuration.put("host", matcher.group(1));
configuration.put("port", Integer.valueOf(matcher.group(2)));
configuration.put("extraParams", "");
CoreDatasource initDatasource = new CoreDatasource();
initDatasource.setId(985188400292302848L);
initDatasource.setName("Demo");
initDatasource.setType("mysql");
initDatasource.setPid(0L);
initDatasource.setConfiguration(JsonUtil.toJSONString(configuration).toString());
initDatasource.setCreateTime(System.currentTimeMillis());
initDatasource.setUpdateTime(System.currentTimeMillis());
initDatasource.setCreateBy("1");
initDatasource.setUpdateBy(1L);
initDatasource.setStatus("success");
initDatasource.setTaskStatus("WaitingForExecution");
datasourceMapper.deleteById(985188400292302848L);
datasourceMapper.insert(initDatasource);
}
}
}

View File

@ -0,0 +1,877 @@
package com.stdproject.service.provider;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.JsonPath;
import io.gisbi.extensions.datasource.dto.ApiDefinition;
import io.gisbi.extensions.datasource.dto.ApiDefinitionRequest;
import io.gisbi.exception.DEException;
import io.gisbi.extensions.datasource.dto.DatasetTableDTO;
import io.gisbi.extensions.datasource.dto.DatasourceRequest;
import io.gisbi.extensions.datasource.dto.TableField;
import io.gisbi.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ApiUtils {
private static String path = "['%s']";
public static ObjectMapper objectMapper = CommonBeanFactory.getBean(ObjectMapper.class);
private static TypeReference<List<Object>> listTypeReference = new TypeReference<List<Object>>() {
};
private static TypeReference<List<Map<String, Object>>> listForMapTypeReference = new TypeReference<List<Map<String, Object>>>() {
};
/**
* 从数据源配置中解析并获取API数据表信息列表
*
* @param datasourceRequest 数据源请求对象包含数据源配置信息
* @return 数据集表DTO列表包含表名称显示名称及所属数据源ID
* @throws DEException 当数据处理过程中出现异常时抛出
*/
public static List<DatasetTableDTO> getApiTables(DatasourceRequest datasourceRequest) throws DEException {
List<DatasetTableDTO> tableDescs = new ArrayList<>();
// 定义API配置的反序列化类型引用
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
// 从数据源配置中解析API定义列表
List<ApiDefinition> apiDefinitionList = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
for (ApiDefinition apiDefinition : apiDefinitionList) {
// 过滤空对象和参数类型配置
if (apiDefinition == null) {
continue;
}
if (StringUtils.isNotEmpty(apiDefinition.getType()) && apiDefinition.getType().equalsIgnoreCase("params")) {
continue;
}
// 构建数据集表信息对象
DatasetTableDTO datasetTableDTO = new DatasetTableDTO();
datasetTableDTO.setTableName(apiDefinition.getDeTableName());
datasetTableDTO.setName(apiDefinition.getName());
datasetTableDTO.setDatasourceId(datasourceRequest.getDatasource().getId());
tableDescs.add(datasetTableDTO);
}
return tableDescs;
}
/**
* 将JSON配置字符串解析为表名映射关系
*
* @param configration 输入的JSON配置字符串应包含包含"name""deTableName"字段的数组对象
* @return 返回键值对映射key为配置中的name字段值value为对应的deTableName字段值
* @throws DEException 当JSON解析失败时抛出异常
*/
public static Map<String, String> getTableNamesMap(String configration) throws DEException {
Map<String, String> result = new HashMap<>();
try {
// 解析JSON根节点并遍历数组元素
JsonNode rootNode = objectMapper.readTree(configration);
for (int i = 0; i < rootNode.size(); i++) {
// 提取每个元素的name和deTableName字段构建映射关系
result.put(rootNode.get(i).get("name").asText(), rootNode.get(i).get("deTableName").asText());
}
} catch (Exception e) {
// 统一将底层异常转换为领域异常抛出
DEException.throwException(e);
}
return result;
}
public static Map<String, Object> fetchApiResultField(DatasourceRequest datasourceRequest) throws DEException {
Map<String, Object> result = new HashMap<>();
List<String[]> dataList = new ArrayList<>();
List<TableField> fieldList = new ArrayList<>();
ApiDefinition apiDefinition = getApiDefinition(datasourceRequest);
if (apiDefinition == null) {
DEException.throwException("未找到");
}
if (apiDefinition.getRequest().getPage() != null && apiDefinition.getRequest().getPage().getPageType() != null && !apiDefinition.getRequest().getPage().getPageType().equalsIgnoreCase("empty")) {
String response = execHttpRequest(false, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
fieldList = getTableFields(apiDefinition);
result.put("fieldList", fieldList);
if (apiDefinition.getRequest().getPage().getPageType().equalsIgnoreCase("pageNumber")) {
int pageCount = Integer.valueOf(JsonPath.read(response, apiDefinition.getRequest().getPage().getResponseData().get(0).getResolutionPath()).toString());
int beginPage = Integer.valueOf(apiDefinition.getRequest().getPage().getRequestData().get(0).getParameterDefaultValue());
if (apiDefinition.getRequest().getPage().getResponseData().get(0).getResolutionPathType().equalsIgnoreCase("totalNumber")) {
pageCount = pageCount / Integer.valueOf(apiDefinition.getRequest().getPage().getRequestData().get(1).getParameterDefaultValue()) + 1;
}
for (int i = beginPage; i <= pageCount; i++) {
apiDefinition.getRequest().getPage().getRequestData().get(0).setParameterDefaultValue(String.valueOf(i));
response = execHttpRequest(false, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
dataList.addAll(fetchResult(response, apiDefinition));
}
}
if (apiDefinition.getRequest().getPage().getPageType().equalsIgnoreCase("cursor")) {
dataList.addAll(fetchResult(response, apiDefinition));
String cursor = null;
try {
cursor = JsonPath.read(response, apiDefinition.getRequest().getPage().getResponseData().get(0).getResolutionPath()).toString();
} catch (Exception e) {
}
while (cursor != null) {
apiDefinition.getRequest().getPage().getRequestData().get(0).setParameterDefaultValue(cursor);
response = execHttpRequest(false, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
dataList.addAll(fetchResult(response, apiDefinition));
try {
if (cursor.equalsIgnoreCase(JsonPath.read(response, apiDefinition.getRequest().getPage().getResponseData().get(0).getResolutionPath()).toString())) {
cursor = null;
} else {
cursor = JsonPath.read(response, apiDefinition.getRequest().getPage().getResponseData().get(0).getResolutionPath()).toString();
}
} catch (Exception e) {
cursor = null;
}
}
}
result.put("dataList", dataList);
return result;
} else {
String response = execHttpRequest(false, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
fieldList = getTableFields(apiDefinition);
result.put("fieldList", fieldList);
dataList = fetchResult(response, apiDefinition);
result.put("dataList", dataList);
return result;
}
}
private static List<TableField> getTableFields(ApiDefinition apiDefinition) throws DEException {
return apiDefinition.getFields();
}
public static List<TableField> getTableFields(DatasourceRequest datasourceRequest) throws DEException {
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<TableField> tableFields = new ArrayList<>();
try {
List<ApiDefinition> lists = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
for (ApiDefinition apiDefinition : lists) {
if (datasourceRequest.getTable().equalsIgnoreCase(apiDefinition.getDeTableName())) {
tableFields = getTableFields(apiDefinition);
}
}
} catch (Exception e) {
}
return tableFields;
}
public static String checkAPIStatus(DatasourceRequest datasourceRequest) throws Exception {
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<ApiDefinition> apiDefinitionList = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
List<ObjectNode> status = new ArrayList();
for (ApiDefinition apiDefinition : apiDefinitionList) {
if (apiDefinition == null || (apiDefinition.getType() != null && apiDefinition.getType().equalsIgnoreCase("params"))) {
continue;
}
datasourceRequest.setTable(apiDefinition.getName());
ObjectNode apiItemStatuses = objectMapper.createObjectNode();
try {
getData(datasourceRequest);
apiItemStatuses.put("name", apiDefinition.getName());
apiItemStatuses.put("status", "Success");
} catch (Exception e) {
LogUtil.error("API status Error: " + datasourceRequest.getDatasource().getName() + "-" + apiDefinition.getName(), e);
apiItemStatuses.put("name", apiDefinition.getName());
apiItemStatuses.put("status", "Error");
}
status.add(apiItemStatuses);
}
return JsonUtil.toJSONString(status).toString();
}
private static List<String[]> getData(DatasourceRequest datasourceRequest) throws Exception {
ApiDefinition apiDefinition = getApiDefinition(datasourceRequest);
if (apiDefinition == null) {
DEException.throwException("未找到");
}
String response = execHttpRequest(true, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
return fetchResult(response, apiDefinition);
}
public static String execHttpRequest(boolean preview, ApiDefinition api, int socketTimeout, List<ApiDefinition> paramsList) {
ApiDefinition apiDefinition = new ApiDefinition();
BeanUtils.copyBean(apiDefinition, api);
if (apiDefinition.getRequest().getPage() != null && apiDefinition.getRequest().getPage().getPageType() != null && apiDefinition.getRequest().getPage().getPageType().equalsIgnoreCase("pageNumber")) {
apiDefinition.setUrl(apiDefinition.getUrl().replace(apiDefinition.getRequest().getPage().getRequestData().get(0).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(0).getParameterDefaultValue()).replace(apiDefinition.getRequest().getPage().getRequestData().get(1).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(1).getParameterDefaultValue()));
apiDefinition.setRequest(JsonUtil.parseObject(JsonUtil.toJSONString(apiDefinition.getRequest()).toString().replace(apiDefinition.getRequest().getPage().getRequestData().get(0).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(0).getParameterDefaultValue()).replace(apiDefinition.getRequest().getPage().getRequestData().get(1).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(1).getParameterDefaultValue()), ApiDefinitionRequest.class));
}
if (apiDefinition.getRequest().getPage() != null && apiDefinition.getRequest().getPage().getPageType() != null && apiDefinition.getRequest().getPage().getPageType().equalsIgnoreCase("cursor")) {
apiDefinition.setUrl(apiDefinition.getUrl().replace(apiDefinition.getRequest().getPage().getRequestData().get(0).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(0).getParameterDefaultValue()).replace(apiDefinition.getRequest().getPage().getRequestData().get(1).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(1).getParameterDefaultValue()));
String defaultCursor = apiDefinition.getRequest().getPage().getRequestData().get(0).getParameterDefaultValue();
apiDefinition.setRequest(JsonUtil.parseObject(JsonUtil.toJSONString(apiDefinition.getRequest()).toString().replace(apiDefinition.getRequest().getPage().getRequestData().get(0).getBuiltInParameterName(), StringUtils.isEmpty(defaultCursor) ? "" : defaultCursor).replace(apiDefinition.getRequest().getPage().getRequestData().get(1).getBuiltInParameterName(), apiDefinition.getRequest().getPage().getRequestData().get(1).getParameterDefaultValue()), ApiDefinitionRequest.class));
}
String response = "";
HttpClientConfig httpClientConfig = new HttpClientConfig();
httpClientConfig.setSocketTimeout(socketTimeout * 1000);
ApiDefinitionRequest apiDefinitionRequest = apiDefinition.getRequest();
for (Map header : apiDefinitionRequest.getHeaders()) {
if (header.get("name") != null && StringUtils.isNotEmpty(header.get("name").toString()) && header.get("value") != null && StringUtils.isNotEmpty(header.get("value").toString())) {
if (header.get("nameType") != null && header.get("nameType").toString().equalsIgnoreCase("params")) {
String param = header.get("value").toString();
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(true, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
httpClientConfig.addHeader(header.get("name").toString(), dataList.get(0)[i]);
}
}
}
}
} else if (header.get("nameType") != null && header.get("nameType").toString().equalsIgnoreCase("custom")) {
List<String> params = new ArrayList<>();
String regex = "\\$\\{(.*?)\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(header.get("value").toString());
while (matcher.find()) {
params.add(matcher.group(1));
}
String result = header.get("value").toString();
for (String param : params) {
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(true, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
result = result.replace("${" + param + "}", dataList.get(0)[i]);
}
}
}
}
}
httpClientConfig.addHeader(header.get("name").toString(), result);
} else if (header.get("nameType") != null && header.get("nameType").toString().equalsIgnoreCase("timeFun")) {
String timeFormat = header.get("value").toString();
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
if (StringUtils.isNotEmpty(timeFormat) && timeFormat.split(" ")[0].equalsIgnoreCase("currentDay")) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat.split(" ")[1]);
httpClientConfig.addHeader(header.get("name").toString(), simpleDateFormat.format(date));
}
} else {
httpClientConfig.addHeader(header.get("name").toString(), header.get("value").toString());
}
}
}
if (apiDefinitionRequest.getAuthManager() != null
&& StringUtils.isNotBlank(apiDefinitionRequest.getAuthManager().getUsername())
&& StringUtils.isNotBlank(apiDefinitionRequest.getAuthManager().getPassword())
&& apiDefinitionRequest.getAuthManager().getVerification().equals("Basic Auth")) {
String authValue = "Basic " + Base64.getUrlEncoder().encodeToString((apiDefinitionRequest.getAuthManager().getUsername()
+ ":" + apiDefinitionRequest.getAuthManager().getPassword()).getBytes());
httpClientConfig.addHeader("Authorization", authValue);
}
List<String> params = new ArrayList<>();
for (Map<String, String> argument : apiDefinition.getRequest().getArguments()) {
if (StringUtils.isNotEmpty(argument.get("name")) && StringUtils.isNotEmpty(argument.get("value"))) {
if (argument.get("nameType") != null && argument.get("nameType").toString().equalsIgnoreCase("params")) {
String param = argument.get("value").toString();
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getOriginName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(true, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
params.add(argument.get("name") + "=" + dataList.get(0)[i]);
}
}
}
}
} else if (argument.get("nameType") != null && argument.get("nameType").toString().equalsIgnoreCase("custom")) {
List<String> arrayList = new ArrayList<>();
String regex = "\\$\\{(.*?)\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(argument.get("value").toString());
while (matcher.find()) {
arrayList.add(matcher.group(1));
}
String result = argument.get("value").toString();
for (String param : arrayList) {
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(true, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
result = result.replace("${" + param + "}", dataList.get(0)[i]);
}
}
}
}
}
params.add(argument.get("name") + "=" + result);
} else if (argument.get("nameType") != null && argument.get("nameType").toString().equalsIgnoreCase("timeFun")) {
String timeFormat = argument.get("value").toString();
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
if (StringUtils.isNotEmpty(timeFormat) && timeFormat.split(" ")[0].equalsIgnoreCase("currentDay")) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat.split(" ")[1]);
params.add(argument.get("name") + "=" + simpleDateFormat.format(date));
}
} else {
params.add(argument.get("name") + "=" + URLEncoder.encode(argument.get("value")));
}
}
}
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(params)) {
apiDefinition.setUrl(apiDefinition.getUrl() + "?" + StringUtils.join(params, "&"));
}
switch (apiDefinition.getMethod()) {
case "GET":
response = HttpClientUtil.get(apiDefinition.getUrl().trim(), httpClientConfig);
break;
case "POST":
if (!apiDefinitionRequest.getBody().keySet().contains("type")) {
DEException.throwException("请求类型不能为空");
}
String type = apiDefinitionRequest.getBody().get("type").toString();
if (StringUtils.equalsAny(type, "JSON", "XML", "Raw")) {
String raw = null;
if (apiDefinitionRequest.getBody().get("raw") != null) {
raw = apiDefinitionRequest.getBody().get("raw").toString();
List<String> bodYparams = new ArrayList<>();
String regex = "\\$\\{(.*?)\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(raw);
while (matcher.find()) {
bodYparams.add(matcher.group(1));
}
for (String param : bodYparams) {
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getOriginName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(false, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
raw = raw.replace("${" + param + "}", dataList.get(0)[i]);
}
}
}
}
}
response = HttpClientUtil.post(apiDefinition.getUrl(), raw, httpClientConfig);
}
}
if (StringUtils.equalsAny(type, "Form_Data", "WWW_FORM")) {
if (apiDefinitionRequest.getBody().get("kvs") != null) {
Map<String, String> body = new HashMap<>();
TypeReference<List<JsonNode>> listTypeReference = new TypeReference<List<JsonNode>>() {
};
List<JsonNode> rootNode = null;
try {
rootNode = objectMapper.readValue(JsonUtil.toJSONString(apiDefinition.getRequest().getBody().get("kvs")).toString(), listTypeReference);
} catch (Exception e) {
e.printStackTrace();
DEException.throwException(e);
}
for (JsonNode jsonNode : rootNode) {
if (jsonNode.has("name") && jsonNode.has("value")) {
if (jsonNode.get("value") != null && StringUtils.isNotEmpty(jsonNode.get("value").asText())) {
if (jsonNode.get("nameType") != null && jsonNode.get("nameType").asText().equalsIgnoreCase("params")) {
String param = jsonNode.get("value").asText();
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getOriginName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(false, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
body.put(jsonNode.get("name").asText(), dataList.get(0)[i]);
}
}
}
}
} else if (jsonNode.get("nameType") != null && jsonNode.get("nameType").asText().equalsIgnoreCase("custom")) {
List<String> bodYparams = new ArrayList<>();
String regex = "\\$\\{(.*?)\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(jsonNode.get("value").asText());
while (matcher.find()) {
bodYparams.add(matcher.group(1));
}
String result = jsonNode.get("value").asText();
for (String param : bodYparams) {
for (ApiDefinition definition : paramsList) {
for (int i = 0; i < definition.getFields().size(); i++) {
TableField field = definition.getFields().get(i);
if (field.getOriginName().equalsIgnoreCase(param)) {
String resultStr = execHttpRequest(false, definition, definition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), null);
List<String[]> dataList = fetchResult(resultStr, definition);
if (dataList.size() > 0) {
result = result.replace("${" + param + "}", dataList.get(0)[i]);
}
}
}
}
}
body.put(jsonNode.get("name").asText(), result);
} else if (jsonNode.get("nameType") != null && jsonNode.get("nameType").asText().equalsIgnoreCase("timeFun")) {
String timeFormat = jsonNode.get("value").asText();
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
if (StringUtils.isNotEmpty(timeFormat) && timeFormat.split(" ")[0].equalsIgnoreCase("currentDay")) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat.split(" ")[1]);
body.put(jsonNode.get("name").toString(), simpleDateFormat.format(date));
}
} else {
body.put(jsonNode.get("name").asText(), jsonNode.get("value").asText());
}
}
}
}
response = HttpClientUtil.post(apiDefinition.getUrl(), body, httpClientConfig);
}
}
break;
default:
break;
}
return response;
}
private static void previewNum(List<Map<String, Object>> field) {
for (Map<String, Object> stringObjectMap : field) {
JSONArray newArray = new JSONArray();
if (stringObjectMap.get("value") != null) {
try {
TypeReference<JSONArray> listTypeReference = new TypeReference<JSONArray>() {
};
JSONArray array = objectMapper.readValue(stringObjectMap.get("value").toString(), listTypeReference);
if (array.size() > 100) {
for (int i = 0; i < Math.min(100, array.size()); i++) {
newArray.add(array.get(i));
}
stringObjectMap.put("value", newArray);
}
} catch (Exception e) {
}
}
}
}
public static ApiDefinition checkApiDefinition(DatasourceRequest datasourceRequest) throws DEException {
ApiDefinition apiDefinition = new ApiDefinition();
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<ApiDefinition> apiDefinitionList = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
if (!CollectionUtils.isEmpty(apiDefinitionList)) {
for (ApiDefinition definition : apiDefinitionList) {
if (definition != null && (definition.getType() == null || !definition.getType().equalsIgnoreCase("params"))) {
apiDefinition = definition;
}
}
}
String response = execHttpRequest(true, apiDefinition, apiDefinition.getApiQueryTimeout() == null || apiDefinition.getApiQueryTimeout() <= 0 ? 10 : apiDefinition.getApiQueryTimeout(), params(datasourceRequest));
return checkApiDefinition(apiDefinition, response);
}
private static ApiDefinition checkApiDefinition(ApiDefinition apiDefinition, String response) throws DEException {
if (StringUtils.isEmpty(response)) {
DEException.throwException("该请求返回数据为空");
}
List<Map<String, Object>> fields = new ArrayList<>();
if (apiDefinition.isShowApiStructure() || !apiDefinition.isUseJsonPath()) {
String rootPath;
if (response.startsWith("[")) {
rootPath = "$[*]";
JsonNode jsonArray = null;
try {
jsonArray = objectMapper.readTree(response);
} catch (Exception e) {
DEException.throwException(e);
}
for (Object o : jsonArray) {
handleStr(apiDefinition, o.toString(), fields, rootPath);
}
} else {
rootPath = "$";
handleStr(apiDefinition, response, fields, rootPath);
}
previewNum(fields);
apiDefinition.setJsonFields(fields);
return apiDefinition;
} else {
List<LinkedHashMap> currentData = new ArrayList<>();
try {
Object object = JsonPath.read(response, apiDefinition.getJsonPath());
if (object instanceof List) {
currentData = (List<LinkedHashMap>) object;
} else {
currentData.add((LinkedHashMap) object);
}
} catch (Exception e) {
DEException.throwException(e);
}
int i = 0;
try {
LinkedHashMap data = currentData.get(0);
} catch (Exception e) {
DEException.throwException("数据不符合规范, " + e.getMessage());
}
for (LinkedHashMap data : currentData) {
if (i >= apiDefinition.getPreviewNum()) {
break;
}
if (i == 0) {
for (Object o : data.keySet()) {
Map<String, Object> field = new HashMap<>();
field.put("originName", o.toString());
field.put("name", o.toString());
field.put("type", "STRING");
field.put("checked", true);
field.put("size", 65535);
field.put("deExtractType", 0);
field.put("deType", 0);
field.put("extField", 0);
fields.add(field);
}
}
for (Map<String, Object> field : fields) {
JSONArray array = new JSONArray();
if (field.get("value") != null) {
try {
TypeReference<JSONArray> listTypeReference = new TypeReference<JSONArray>() {
};
array = objectMapper.readValue(field.get("value").toString(), listTypeReference);
} catch (Exception e) {
e.printStackTrace();
DEException.throwException(e);
}
array.add(Optional.ofNullable(data.get(field.get("originName"))).orElse("").toString().replaceAll("\n", " ").replaceAll("\r", " "));
} else {
array.add(Optional.ofNullable(data.get(field.get("originName"))).orElse("").toString().replaceAll("\n", " ").replaceAll("\r", " "));
}
field.put("value", array);
}
i++;
}
apiDefinition.setJsonFields(fields);
return apiDefinition;
}
}
private static void handleStr(ApiDefinition apiDefinition, String jsonStr, List<Map<String, Object>> fields, String rootPath) throws DEException {
if (jsonStr.startsWith("[")) {
TypeReference<List<Object>> listTypeReference = new TypeReference<List<Object>>() {
};
List<Object> jsonArray = null;
try {
jsonArray = objectMapper.readValue(jsonStr, listTypeReference);
} catch (Exception e) {
DEException.throwException(e);
}
for (Object o : jsonArray) {
handleStr(apiDefinition, o.toString(), fields, rootPath);
}
} else {
JsonNode jsonNode = null;
try {
jsonNode = objectMapper.readTree(jsonStr);
} catch (Exception e) {
DEException.throwException(e);
}
Iterator<String> fieldNames = jsonNode.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
String value = jsonNode.get(fieldName).toString();
if (StringUtils.isNotEmpty(value) && !value.startsWith("[") && !value.startsWith("{")) {
value = jsonNode.get(fieldName).asText();
}
if (StringUtils.isNotEmpty(value) && value.startsWith("[")) {
Map<String, Object> o = new HashMap<>();
try {
JsonNode jsonArray = objectMapper.readTree(value);
List<Map<String, Object>> childrenField = new ArrayList<>();
for (JsonNode node : jsonArray) {
if (StringUtils.isNotEmpty(node.toString()) && !node.toString().startsWith("[") && !node.toString().startsWith("{")) {
throw new Exception(node + "is not json type");
}
}
for (JsonNode node : jsonArray) {
handleStr(apiDefinition, node.toString(), childrenField, rootPath + "." + String.format(path, fieldName) + "[*]");
}
o.put("children", childrenField);
o.put("childrenDataType", "LIST");
} catch (Exception e) {
JSONArray array = new JSONArray();
array.add(StringUtils.isNotEmpty(jsonNode.get(fieldName).toString()) ? jsonNode.get(fieldName).toString() : "");
o.put("value", array);
}
o.put("jsonPath", rootPath + "." + String.format(path, fieldName));
setProperty(apiDefinition, o, fieldName);
if (!hasItem(apiDefinition, fields, o)) {
fields.add(o);
}
} else if (StringUtils.isNotEmpty(value) && value.startsWith("{")) {
try {
JsonNode jsonNode1 = objectMapper.readTree(value);
List<Map<String, Object>> children = new ArrayList<>();
handleStr(apiDefinition, value, children, rootPath + "." + String.format(path, fieldName));
Map<String, Object> o = new HashMap<>();
o.put("children", children);
o.put("childrenDataType", "OBJECT");
o.put("jsonPath", rootPath + "." + fieldName);
setProperty(apiDefinition, o, fieldName);
if (!hasItem(apiDefinition, fields, o)) {
fields.add(o);
}
} catch (Exception e) {
Map<String, Object> o = new HashMap<>();
o.put("jsonPath", rootPath + "." + String.format(path, fieldName));
setProperty(apiDefinition, o, fieldName);
JSONArray array = new JSONArray();
array.add(StringUtils.isNotEmpty(value) ? value : "");
o.put("value", array);
if (!hasItem(apiDefinition, fields, o)) {
fields.add(o);
}
}
} else {
Map<String, Object> o = new HashMap<>();
o.put("jsonPath", rootPath + "." + String.format(path, fieldName));
setProperty(apiDefinition, o, fieldName);
JSONArray array = new JSONArray();
array.add(StringUtils.isNotEmpty(value) ? value : "");
o.put("value", array);
if (!hasItem(apiDefinition, fields, o)) {
fields.add(o);
}
}
}
}
}
private static void setProperty(ApiDefinition apiDefinition, Map<String, Object> o, String s) {
o.put("originName", s);
o.put("name", s);
o.put("type", "STRING");
o.put("size", 65535);
o.put("deExtractType", 0);
o.put("deType", 0);
o.put("checked", false);
if (!apiDefinition.isUseJsonPath()) {
for (TableField field : apiDefinition.getFields()) {
if (!ObjectUtils.isEmpty(o.get("jsonPath")) && StringUtils.isNotEmpty(field.getJsonPath()) && field.getJsonPath().equals(o.get("jsonPath").toString())) {
o.put("checked", true);
o.put("name", field.getName());
o.put("primaryKey", field.isPrimaryKey());
o.put("length", field.getLength());
o.put("deExtractType", field.getDeExtractType());
}
}
}
}
private static boolean hasItem(ApiDefinition apiDefinition, List<Map<String, Object>> fields, Map<String, Object> item) throws DEException {
boolean has = false;
for (Map<String, Object> field : fields) {
if (field.get("jsonPath").equals(item.get("jsonPath"))) {
has = true;
mergeField(field, item);
mergeValue(field, apiDefinition, item);
break;
}
}
return has;
}
private static void mergeField(Map<String, Object> field, Map<String, Object> item) throws DEException {
if (item.get("children") != null) {
List<Map<String, Object>> fieldChildren = null;
List<Map<String, Object>> itemChildren = null;
try {
fieldChildren = objectMapper.readValue(JsonUtil.toJSONString(field.get("children")).toString(), listForMapTypeReference);
itemChildren = objectMapper.readValue(JsonUtil.toJSONString(item.get("children")).toString(), listForMapTypeReference);
} catch (Exception e) {
DEException.throwException(e);
}
if (fieldChildren == null) {
fieldChildren = new ArrayList<>();
}
for (Map<String, Object> itemChild : itemChildren) {
boolean hasKey = false;
for (Map<String, Object> fieldChild : fieldChildren) {
if (itemChild.get("jsonPath").toString().equals(fieldChild.get("jsonPath").toString())) {
mergeField(fieldChild, itemChild);
hasKey = true;
}
}
if (!hasKey) {
fieldChildren.add(itemChild);
}
}
}
}
private static void mergeValue(Map<String, Object> field, ApiDefinition apiDefinition, Map<String, Object> item) throws DEException {
TypeReference<JSONArray> listTypeReference = new TypeReference<JSONArray>() {
};
try {
if (!ObjectUtils.isEmpty(field.get("value")) && !ObjectUtils.isEmpty(item.get("value"))) {
JSONArray array = objectMapper.readValue(JsonUtil.toJSONString(field.get("value")).toString(), listTypeReference);
array.add(objectMapper.readValue(JsonUtil.toJSONString(item.get("value")).toString(), listTypeReference).get(0));
field.put("value", array);
}
if (!ObjectUtils.isEmpty(field.get("children")) && !ObjectUtils.isEmpty(item.get("children"))) {
List<Map<String, Object>> fieldChildren = objectMapper.readValue(JsonUtil.toJSONString(field.get("children")).toString(), listForMapTypeReference);
List<Map<String, Object>> itemChildren = objectMapper.readValue(JsonUtil.toJSONString(item.get("children")).toString(), listForMapTypeReference);
List<Map<String, Object>> fieldArrayChildren = new ArrayList<>();
for (Map<String, Object> fieldChild : fieldChildren) {
Map<String, Object> find = null;
for (Map<String, Object> itemChild : itemChildren) {
if (fieldChild.get("jsonPath").toString().equals(itemChild.get("jsonPath").toString())) {
find = itemChild;
}
}
if (find != null) {
mergeValue(fieldChild, apiDefinition, find);
}
fieldArrayChildren.add(fieldChild);
}
field.put("children", fieldArrayChildren);
}
} catch (Exception e) {
e.printStackTrace();
DEException.throwException(e);
}
}
private static List<String[]> fetchResult(String result, ApiDefinition apiDefinition) {
List<String[]> dataList = new LinkedList<>();
if (apiDefinition.isUseJsonPath()) {
List<LinkedHashMap> currentData = new ArrayList<>();
Object object = JsonPath.read(result, apiDefinition.getJsonPath());
if (object instanceof List) {
currentData = (List<LinkedHashMap>) object;
} else {
currentData.add((LinkedHashMap) object);
}
for (LinkedHashMap data : currentData) {
String[] row = new String[apiDefinition.getFields().size()];
int i = 0;
for (TableField field : apiDefinition.getFields()) {
row[i] = Optional.ofNullable(data.get(field.getOriginName())).orElse("").toString().replaceAll("\n", " ").replaceAll("\r", " ");
i++;
}
dataList.add(row);
}
} else {
List<String> jsonPaths = apiDefinition.getFields().stream().map(TableField::getJsonPath).collect(Collectors.toList());
Long maxLength = 0l;
List<List<String>> columnDataList = new ArrayList<>();
for (int i = 0; i < jsonPaths.size(); i++) {
List<String> data = new ArrayList<>();
Object object = JsonPath.read(result, jsonPaths.get(i));
if (object instanceof List && jsonPaths.get(i).contains("[*]")) {
data = (List<String>) object;
} else {
if (object != null) {
data.add(object.toString());
}
}
maxLength = maxLength > data.size() ? maxLength : data.size();
columnDataList.add(data);
}
for (int i = 0; i < maxLength; i++) {
String[] row = new String[apiDefinition.getFields().size()];
dataList.add(row);
}
for (int i = 0; i < columnDataList.size(); i++) {
for (int j = 0; j < columnDataList.get(i).size(); j++) {
dataList.get(j)[i] = Optional.ofNullable(String.valueOf(columnDataList.get(i).get(j))).orElse("").replaceAll("\n", " ").replaceAll("\r", " ");
}
}
}
return dataList;
}
private static List<ApiDefinition> params(DatasourceRequest datasourceRequest) {
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<ApiDefinition> apiDefinitionListTemp = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
return apiDefinitionListTemp.stream().filter(apiDefinition -> apiDefinition != null && apiDefinition.getType() != null && apiDefinition.getType().equalsIgnoreCase("params")).collect(Collectors.toList());
}
private static ApiDefinition getApiDefinition(DatasourceRequest datasourceRequest) throws DEException {
List<ApiDefinition> apiDefinitionList = new ArrayList<>();
TypeReference<List<ApiDefinition>> listTypeReference = new TypeReference<List<ApiDefinition>>() {
};
List<ApiDefinition> apiDefinitionListTemp = JsonUtil.parseList(datasourceRequest.getDatasource().getConfiguration(), listTypeReference);
if (!CollectionUtils.isEmpty(apiDefinitionListTemp)) {
for (ApiDefinition apiDefinition : apiDefinitionListTemp) {
if (apiDefinition == null || apiDefinition.getType() == null || apiDefinition.getType().equalsIgnoreCase("params")) {
continue;
}
if (apiDefinition.getDeTableName().equalsIgnoreCase(datasourceRequest.getTable()) || apiDefinition.getName().equalsIgnoreCase(datasourceRequest.getTable())) {
apiDefinitionList.add(apiDefinition);
}
}
}
if (CollectionUtils.isEmpty(apiDefinitionList)) {
DEException.throwException("未找到API数据表");
}
if (apiDefinitionList.size() > 1) {
DEException.throwException("存在重名的API数据表");
}
ApiDefinition find = null;
for (ApiDefinition apiDefinition : apiDefinitionList) {
if (apiDefinition == null) {
continue;
}
if (apiDefinition.getName().equalsIgnoreCase(datasourceRequest.getTable()) || apiDefinition.getDeTableName().equalsIgnoreCase(datasourceRequest.getTable())) {
find = apiDefinition;
}
}
return find;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Data
@Component("ck")
public class CK extends DatasourceConfiguration {
private String driver = "com.clickhouse.jdbc.ClickHouseDriver";
private String extraParams = "";
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if(StringUtils.isEmpty(extraParams.trim())){
return "jdbc:clickhouse://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
}else {
return "jdbc:clickhouse://HOSTNAME:PORT/DATABASE?EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,39 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Data
@Component("db2")
public class Db2 extends DatasourceConfiguration {
private String driver = "com.ibm.db2.jcc.DB2Driver";
private String extraParams = "";
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if(StringUtils.isEmpty(extraParams.trim())){
if (StringUtils.isEmpty(getSchema())) {
return "jdbc:db2://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
} else {
return "jdbc:db2://HOSTNAME:PORT/DATABASE:currentSchema=SCHEMA;"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("SCHEMA",getSchema().trim());
}
}else {
return "jdbc:db2://HOSTNAME:PORT/DATABASE:EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,14 @@
package com.stdproject.service.type;
import lombok.Data;
@Data
public class Es {
private String url;
private String username;
private String password;
private String version;
private String uri;
}

View File

@ -0,0 +1,11 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@Component("h2")
public class H2 extends DatasourceConfiguration {
private String driver = "org.h2.Driver";
}

View File

@ -0,0 +1,36 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Data
@Component("impala")
public class Impala extends DatasourceConfiguration {
private String driver = "com.cloudera.impala.jdbc.Driver";
private String extraParams = "";
private List<String> illegalParameters = Arrays.asList("autoDeserialize", "queryInterceptors", "statementInterceptors", "detectCustomCollations");
private List<String> showTableSqls = Arrays.asList("show tables");
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if(StringUtils.isEmpty(extraParams.trim())){
return "jdbc:impala://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
}else {
return "jdbc:impala://HOSTNAME:PORT/DATABASE;EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,42 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Data
@Component("mongo")
public class Mongo extends DatasourceConfiguration {
private String driver = "com.mysql.cj.jdbc.Driver";
private String extraParams = "characterEncoding=UTF-8&connectTimeout=5000&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull";
private List<String> illegalParameters = Arrays.asList("autoDeserialize", "queryInterceptors", "statementInterceptors", "detectCustomCollations");
private List<String> showTableSqls = Arrays.asList("show tables");
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if (StringUtils.isEmpty(extraParams.trim())) {
return "jdbc:mysql://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
} else {
for (String illegalParameter : illegalParameters) {
if (getExtraParams().contains(illegalParameter)) {
throw new RuntimeException("Illegal parameter: " + illegalParameter);
}
}
return "jdbc:mysql://HOSTNAME:PORT/DATABASE?EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,48 @@
package com.stdproject.service.type;
import io.gisbi.exception.DEException;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.List;
@Data
@Component("mysql")
public class Mysql extends DatasourceConfiguration {
private String driver = "com.mysql.cj.jdbc.Driver";
private String extraParams = "characterEncoding=UTF-8&connectTimeout=5000&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull";
private List<String> illegalParameters = Arrays.asList("maxAllowedPacket", "autoDeserialize", "queryInterceptors", "statementInterceptors", "detectCustomCollations", "allowloadlocalinfile", "allowUrlInLocalInfile", "allowLoadLocalInfileInPath");
private List<String> showTableSqls = Arrays.asList("show tables");
public String getJdbc() {
if (StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")) {
for (String illegalParameter : illegalParameters) {
if (URLDecoder.decode(getJdbcUrl()).toLowerCase().contains(illegalParameter.toLowerCase()) || URLDecoder.decode(getExtraParams()).contains(illegalParameter.toLowerCase())) {
DEException.throwException("Illegal parameter: " + illegalParameter);
}
}
return getJdbcUrl();
}
if (StringUtils.isEmpty(extraParams.trim())) {
return "jdbc:mysql://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
} else {
for (String illegalParameter : illegalParameters) {
if (URLDecoder.decode(getExtraParams()).toLowerCase().contains(illegalParameter.toLowerCase()) || URLDecoder.decode(getExtraParams()).contains(illegalParameter.toLowerCase())) {
DEException.throwException("Illegal parameter: " + illegalParameter);
}
}
return "jdbc:mysql://HOSTNAME:PORT/DATABASE?EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,30 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Data
@Component("oracle")
public class Oracle extends DatasourceConfiguration {
private String driver = "oracle.jdbc.driver.OracleDriver";
private String extraParams = "";
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if (StringUtils.isNotEmpty(getConnectionType()) && getConnectionType().equalsIgnoreCase("serviceName")) {
return "jdbc:oracle:thin:@HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
}else {
return "jdbc:oracle:thin:@HOSTNAME:PORT:DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
}
}
}

View File

@ -0,0 +1,40 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Data
@Component("pg")
public class Pg extends DatasourceConfiguration {
private String driver = "org.postgresql.Driver";
private String extraParams = "";
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if(StringUtils.isEmpty(extraParams.trim())){
if (StringUtils.isEmpty(getSchema())) {
return "jdbc:postgresql://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
} else {
return "jdbc:postgresql://HOSTNAME:PORT/DATABASE?currentSchema=SCHEMA"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("SCHEMA", getSchema().trim());
}
}else {
return "jdbc:postgresql://HOSTNAME:PORT/DATABASE?EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,23 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Data
@Component("redshift")
public class Redshift extends DatasourceConfiguration {
private String driver = "com.amazon.redshift.jdbc42.Driver";
private String extraParams = "";
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
return "jdbc:redshift://HOSTNAME:PORT/DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
}
}

View File

@ -0,0 +1,36 @@
package com.stdproject.service.type;
import io.gisbi.extensions.datasource.vo.DatasourceConfiguration;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Data
@Component("sqlServer")
public class Sqlserver extends DatasourceConfiguration {
private String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private String extraParams = "";
private List<String> illegalParameters = Arrays.asList("autoDeserialize", "queryInterceptors", "statementInterceptors", "detectCustomCollations");
private List<String> showTableSqls = Arrays.asList("show tables");
public String getJdbc() {
if(StringUtils.isNoneEmpty(getUrlType()) && !getUrlType().equalsIgnoreCase("hostName")){
return getJdbcUrl();
}
if (StringUtils.isEmpty(extraParams.trim())) {
return "jdbc:sqlserver://HOSTNAME:PORT;DatabaseName=DATABASE"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim());
} else {
return "jdbc:sqlserver://HOSTNAME:PORT;DatabaseName=DATABASE;EXTRA_PARAMS"
.replace("HOSTNAME", getLHost().trim())
.replace("PORT", getLPort().toString().trim())
.replace("DATABASE", getDataBase().trim())
.replace("EXTRA_PARAMS", getExtraParams().trim());
}
}
}

View File

@ -0,0 +1,210 @@
package com.stdproject.utils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.UUID;
/**
* 加密解密工具
*
* @Author bi-coder
*/
public class CodingUtil {
private static final String UTF_8 = "UTF-8";
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z" };
/**
* MD5加密
*
* @param src 要加密的串
* @return 加密后的字符串
*/
public static String md5(String src) {
return md5(src, UTF_8);
}
/**
* MD5加密
*
* @param src 要加密的串
* @param charset 加密字符集
* @return 加密后的字符串
*/
public static String md5(String src, String charset) {
try {
byte[] strTemp = StringUtils.isEmpty(charset) ? src.getBytes() : src.getBytes(charset);
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(strTemp);
byte[] md = mdTemp.digest();
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
for (byte byte0 : md) {
str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf];
str[k++] = HEX_DIGITS[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
throw new RuntimeException("MD5 encrypt error:", e);
}
}
/**
* BASE64解密
*
* @param src 待解密的字符串
* @return 解密后的字符串
*/
public static String base64Decoding(String src) {
byte[] b;
String result = null;
if (src != null) {
try {
b = Base64.decodeBase64(src);
result = new String(b, UTF_8);
} catch (Exception e) {
throw new RuntimeException("BASE64 decoding error:", e);
}
}
return result;
}
/**
* BASE64加密
*
* @param src 待加密的字符串
* @return 加密后的字符串
*/
public static String base64Encoding(String src) {
String result = null;
if (src != null) {
try {
result = Base64.encodeBase64String(src.getBytes(UTF_8));
} catch (Exception e) {
throw new RuntimeException("BASE64 encoding error:", e);
}
}
return result;
}
/**
* AES加密
*
* @param src 待加密字符串
* @param secretKey 密钥
* @param iv 向量
* @return 加密后字符串
*/
public static String aesEncrypt(String src, String secretKey, String iv) {
if (StringUtils.isBlank(secretKey)) {
throw new RuntimeException("secretKey is empty");
}
try {
byte[] raw = secretKey.getBytes(UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
// "算法/模式/补码方式" ECB
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv1);
byte[] encrypted = cipher.doFinal(src.getBytes(UTF_8));
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
throw new RuntimeException("AES encrypt error:", e);
}
}
/**
* AES 解密
*
* @param src 待解密字符串
* @param secretKey 密钥
* @param iv 向量
* @return 解密后字符串
*/
public static String aesDecrypt(String src, String secretKey, String iv) {
if (StringUtils.isBlank(secretKey)) {
throw new RuntimeException("secretKey is empty");
}
try {
byte[] raw = secretKey.getBytes(UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1);
byte[] encrypted1 = Base64.decodeBase64(src);
byte[] original = cipher.doFinal(encrypted1);
return new String(original, UTF_8);
} catch (BadPaddingException | IllegalBlockSizeException e) {
// 解密的原字符串为非加密字符串则直接返回原字符串
return src;
} catch (Exception e) {
throw new RuntimeException("decrypt errorplease check parameters", e);
}
}
public static String secretKey() {
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
return Base64.encodeBase64String(secretKey.getEncoded());
} catch (Exception e) {
throw new RuntimeException("generate secretKey error", e);
}
}
public static boolean isNumeric(String str){
for (int i = str.length();--i>=0;){
if (!Character.isDigit(str.charAt(i))){
return false;
}
}
return true;
}
public static String shortUuid() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString();
}
public static Integer string2Integer(String str) {
StringBuffer sb = new StringBuffer();
if (StringUtils.isBlank(str)) return null;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isDigit(c)) {
sb.append(c);
}
}
return sb.length() > 0 ? Integer.parseInt(sb.toString()) : null;
}
}

View File

@ -0,0 +1,44 @@
package com.stdproject.utils;
import io.gisbi.utils.BeanUtils;
import java.util.List;
import java.util.stream.Collectors;
public class EncryptUtils extends CodingUtil {
private static final String secretKey = "www.fit2cloud.co";
private static final String iv = "1234567890123456";
public static Object aesEncrypt(Object o) {
if (o == null) {
return null;
}
return aesEncrypt(o.toString(), secretKey, iv);
}
public static Object aesDecrypt(Object o) {
if (o == null) {
return null;
}
return aesDecrypt(o.toString(), secretKey, iv);
}
public static <T> Object aesDecrypt(List<T> o, String attrName) {
if (o == null) {
return null;
}
return o.stream()
.filter(element -> BeanUtils.getFieldValueByName(attrName, element) != null)
.peek(element -> BeanUtils.setFieldValueByName(element, attrName, aesDecrypt(BeanUtils.getFieldValueByName(attrName, element).toString(), secretKey, iv), String.class))
.collect(Collectors.toList());
}
public static Object md5Encrypt(Object o) {
if (o == null) {
return null;
}
return md5(o.toString());
}
}

View File

@ -0,0 +1,61 @@
package com.stdproject.utils;
import java.util.Arrays;
import java.util.List;
/**
* @Author bi-coder
*/
public class FieldUtils {
public static int transType2DeType(final String type) {
List<String> text = Arrays.asList("CHAR", "VARCHAR", "TEXT", "TINYTEXT", "MEDIUMTEXT", "LONGTEXT", "ENUM", "ANY", "STRING", "BOOL", "BOOLEAN");
List<String> time = Arrays.asList("DATE", "TIME", "YEAR", "DATETIME", "TIMESTAMP", "DATEV2", "DATETIMEV2", "DATETIME2", "DATETIMEOFFSET", "SMALLDATETIME", "DATETIME64", "_TIMESTAMPTZ", "TIMESTAMPTZ");
List<String> num = Arrays.asList("INT", "SMALLINT", "MEDIUMINT", "INTEGER", "BIGINT", "LONG", "INT2", "INT4", "INT8", "int2", "int4", "int8", "INT16", "INT32", "INT64", "UINT8", "UINT16", "UINT32", "UINT64");
List<String> doubleList = Arrays.asList("NUMBER", "FLOAT", "DOUBLE", "DECIMAL", "REAL", "MONEY", "NUMERIC", "float4", "float8", "FLOAT4", "FLOAT8", "DECFLOAT", "FLOAT32", "FLOAT64");
List<String> boolType = Arrays.asList("BIT", "TINYINT");
if (boolType.contains(type)) {
return 4;// 布尔
}
if (doubleList.contains(type)) {
return 3;// 浮点
}
if (num.contains(type)) {
return 2;// 整型
}
if (time.contains(type)) {
return 1;// 时间
}
if (text.contains(type)) {
return 0;// 文本
}
if (boolType.stream().anyMatch(l -> type.contains(l))) {
return 4;// 布尔
}
if (doubleList.stream().anyMatch(l -> type.contains(l))) {
return 3;// 浮点
}
if (num.stream().anyMatch(l -> type.contains(l))) {
return 2;// 整型
}
if (time.stream().anyMatch(l -> type.contains(l))) {
return 1;// 时间
}
return 0;// 文本
}
public static String transDeType2DQ(int deType) {
switch (deType) {
case 0:
case 1:
case 5:
return "d";
case 2:
case 3:
case 4:
return "q";
default:
return "d";
}
}
}

View File

@ -216,4 +216,5 @@ public class FileUtils {
return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
}

View File

@ -28,6 +28,9 @@ public class JwtUtils {
@Value("${spring.security.jwt.expiration-ms}")
private Long expirationMs;
@Value("${spring.security.jwt.refresh-expiration-ms}")
private Long refreshExpirationMs;
/**
* 生成JWT令牌
*
@ -62,6 +65,33 @@ public class JwtUtils {
.compact();
}
/**
* 创建带刷新时间的 Token
*/
private String createRefreshToken(Map<String, Object> claims, String subject) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + refreshExpirationMs);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(getSigningKey(), SignatureAlgorithm.HS512)
.compact();
}
/**
* 生成 Refresh Token
*/
public String generateRefreshToken(String username, String userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", userId);
claims.put("username", username);
return createRefreshToken(claims, username);
}
/**
* 从JWT令牌中获取用户名
*
@ -165,4 +195,4 @@ public class JwtUtils {
public interface ClaimsResolver<T> {
T resolve(Claims claims);
}
}
}

View File

@ -16,6 +16,8 @@ spring:
active: ${SPRING_PROFILES_ACTIVE:dev}
application:
name: stdproject-backend
main:
allow-bean-definition-overriding: true
datasource:
url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true}
username: ${DB_USERNAME:root}
@ -55,8 +57,8 @@ spring:
jwt:
enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证
secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()}
expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时)
refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天)
expiration-ms: ${JWT_EXPIRATION:1800000} # Token 过期时间 (例如: 24小时)
refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:1800000} # 刷新Token过期时间 (例如: 30分钟)
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置
@ -147,7 +149,7 @@ spring:
on-profile: dev
security:
jwt:
enabled: true
enabled: false
logging:
level:
com.stdproject: DEBUG
@ -155,7 +157,7 @@ logging:
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #org.apache.ibatis.logging.nologging.NoLoggingImpl
springdoc:
swagger-ui:
enabled: true