feat(DataExtractController):新增规则版本测试

dev
gtl 2024-05-12 12:32:17 +08:00
parent 7793e99331
commit 7496035269
58 changed files with 895 additions and 310 deletions

View File

@ -1,5 +1,6 @@
package com.ruoyi.dataAsset.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.dataAsset.domain.DataSource;
@ -11,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import java.util.List;
import java.util.Map;
/**
*

View File

@ -3,7 +3,6 @@ package com.ruoyi.dataAsset.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import java.util.HashMap;
import java.util.Map;
@ -26,4 +25,8 @@ public class DruidDataSourceFactory {
public void put(Long id,DruidDataSource druidDataSource){
this.druidDataSourceMap.put(id,druidDataSource);
}
public DruidDataSource get(Long id){
return this.druidDataSourceMap.get(id);
}
}

View File

@ -37,20 +37,23 @@ public class DataSourceUtil {
* @return
*/
public static String confirmUrl(DataSource dataSource){
String url="jdbc:"+dataSource.getDatabaseType()+dataSource.getIp()+":"+dataSource.getPort();
StringBuilder url= new StringBuilder("jdbc:" + dataSource.getDatabaseType() + dataSource.getIp() + ":" + dataSource.getPort());
String databaseType = dataSource.getDatabaseType();
if(databaseType.contains("mysql")){
url+="/"+dataSource.getDatabases();
url.append("/").append(dataSource.getDatabases());
if(StringUtils.isNotEmpty(dataSource.getConnectionParameter())){
url+="?"+dataSource.getConnectionParameter();
url.append("?").append(dataSource.getConnectionParameter());
}
}else if(databaseType.contains("sqlserver")){
url+=";DatabaseName="+dataSource.getDatabases()+";";
url.append(";DatabaseName=").append(dataSource.getDatabases()).append(";");
if(StringUtils.isNotEmpty(dataSource.getConnectionParameter())){
url+=dataSource.getConnectionParameter()+";";
String[] params = dataSource.getConnectionParameter().split("&");
for (String param : params) {
url.append(param).append(";");
}
}
}
return url;
return url.toString();
}
/**

View File

@ -152,7 +152,6 @@ public class DataSourceServiceImpl extends ServiceImpl<DataSourceMapper, DataSou
//修改数据
this.updateById(dataSource);
result.close();
druidDatasource.close();
} catch (SQLException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}

View File

@ -10,93 +10,16 @@
</parent>
<artifactId>ruoyi-data_transform</artifactId>
<packaging>pom</packaging>
<description>ruoyi-data_transform数据转换模块</description>
<modules>
<module>ruoyi-data_transform-common</module>
<module>ruoyi-data_transform-remote</module>
<module>ruoyi-data_transform-server</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- MuYu 公共 安全模块 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-security</artifactId>
</dependency>
<!-- MuYu 公共 swagger -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-swagger</artifactId>
</dependency>
<!-- 数据资产客户端模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-data_asset-client</artifactId>
<version>3.6.3</version>
</dependency>
<!-- 规则引擎客户端模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-rule_engine-client</artifactId>
<version>3.6.3</version>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- MuYu Common DataScope -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-datascope</artifactId>
</dependency>
<!-- MuYu Common Swagger -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-swagger</artifactId>
</dependency>
<!-- Sql Server 驱动 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.0.jre8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>ruoyi-data_transform</artifactId>
<version>3.6.3</version>
</parent>
<artifactId>ruoyi-data_transform-common</artifactId>
<description>ruoyi-data_transform-common数据转换公共模块</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- MuYu 公共 安全模块 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-security</artifactId>
</dependency>
<!-- MuYu 公共 swagger -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-swagger</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- MuYu Common DataScope -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-datascope</artifactId>
</dependency>
<!-- MuYu Common Swagger -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-common-swagger</artifactId>
</dependency>
<!-- Sql Server 驱动 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.4.0.jre8</version>
</dependency>
<!-- 数据资产客户端模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-data_asset-client</artifactId>
<version>3.6.3</version>
</dependency>
<!-- 规则引擎客户端模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-rule_engine-client</artifactId>
<version>3.6.3</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
package com.ruoyi.dataTransform.domain.req;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
*
* @ClassName RandomDataReq
* @Author
* @Date 2024/5/11 15:37
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "RandomDataReq", description = "随机数据")
public class RandomDataReq {
/**
*
*/
private Long dataSourceId;
/**
*
*/
private String tableName;
/**
*
*/
private Integer scope;
}

View File

@ -0,0 +1,59 @@
package com.ruoyi.dataTransform.domain.req;
import com.ruoyi.ruleEngine.client.model.DataModel;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
*
* @ClassName TestDataReq
* @Author
* @Date 2024/5/11 15:37
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "TestDataReq", description = "测试数据")
public class TestDataReq {
/**
*
*/
private Long versionId;
/**
*
*/
private String versionClass;
/**
*
*/
private Integer scope;
/**
*
*/
private String ruleContent;
/**
*
*/
private DataModel dataModel;
/**
*
*/
private List<String> keys;
/**
*
*/
private List<List<DataModel>> recordsList;
}

View File

@ -0,0 +1,105 @@
package com.ruoyi.dataTransform.util;
import com.ruoyi.ruleEngine.client.model.DataModel;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
*
* @ClassName DataExtractUtil
* @Author
* @Date 2024/5/6 20:51
*/
public class DataExtractUtil {
private static final String RANDOM_SOME_SQL="select * from table_name";
private static final String RANDOM_ONE_SQL="select t1.* from table_name as t1 join (select rand()*(select max(primary_key) from table_name) as primary_key ) as t2 on t1.primary_key>t2.primary_key";
public static List<List<DataModel>> getRecordsModels(Connection connection,String tableName){
List<List<DataModel>> recordsModels=new ArrayList<>();
try {
String needSql = RANDOM_SOME_SQL.replaceAll("table_name", tableName);
if(connection.getMetaData().getDatabaseProductName().contains("MySQL")){
needSql+=" limit 10;";
}else {
needSql+=" order by primary_key offset 0 rows fetch next 10 rows only;";
}
String primaryKey = getPrimaryKey(connection, tableName);
if(Objects.nonNull(primaryKey)){
needSql = needSql.replaceAll("primary_key",primaryKey);
}
PreparedStatement preparedStatement = connection.prepareStatement(needSql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
List<DataModel> dataModels=new ArrayList<>();
setDataModels(dataModels,resultSet);
recordsModels.add(dataModels);
}
resultSet.close();
preparedStatement.close();
connection.close();
} catch (SQLException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
return recordsModels;
}
public static List<DataModel> getDataModels(Connection connection,String tableName){
List<DataModel> dataModels=new ArrayList<>();
try {
String needSql = RANDOM_ONE_SQL.replaceAll("table_name", tableName);
if(connection.getMetaData().getDatabaseProductName().contains("MySQL")){
needSql+=" limit 1;";
}else {
needSql+=" order by primary_key offset 0 rows fetch next 1 rows only;";
}
String primaryKey = getPrimaryKey(connection, tableName);
if(Objects.nonNull(primaryKey)){
needSql = needSql.replaceAll("primary_key",primaryKey);
}
PreparedStatement preparedStatement = connection.prepareStatement(needSql);
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
setDataModels(dataModels,resultSet);
}
resultSet.close();
preparedStatement.close();
connection.close();
} catch (SQLException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
return dataModels;
}
public static void setDataModels(List<DataModel> dataModels,ResultSet resultSet) throws SQLException, ClassNotFoundException {
int index=1;
ResultSetMetaData data = resultSet.getMetaData();
int columnCount = data.getColumnCount();
while (index<=columnCount){
DataModel dataModel = DataModel.builder()
.key(data.getColumnName(index))
.value(resultSet.getString(index))
.sourceType(data.getColumnTypeName(index))
.processType(data.getColumnClassName(index))
.processClass(Class.forName(data.getColumnClassName(index)))
.build();
dataModels.add(dataModel);
index++;
}
}
public static String getPrimaryKey(Connection connection,String tableName) throws SQLException {
ResultSet primaryKeys = connection.getMetaData().getPrimaryKeys(connection.getCatalog(), null, tableName);
String primaryKeyName=null;
while (primaryKeys.next()){
primaryKeyName=primaryKeys.getString("COLUMN_NAME");
}
primaryKeys.close();
return primaryKeyName;
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>ruoyi-data_transform</artifactId>
<version>3.6.3</version>
</parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-data_transform-remote</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>ruoyi-data_transform</artifactId>
<version>3.6.3</version>
</parent>
<artifactId>ruoyi-data_transform-server</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 数据转换公共模块 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>ruoyi-data_transform-common</artifactId>
<version>3.6.3</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 加入maven deploy插件当在deploy时忽略些model-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,37 @@
package com.ruoyi.dataTransform.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.dataTransform.domain.req.RandomDataReq;
import com.ruoyi.dataTransform.service.DataExtractService;
import com.ruoyi.ruleEngine.client.model.DataModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
*
* @ClassName DataExtractController
* @Author
* @Date 2024/5/9 10:56
*/
@Api(tags = "数据抽取")
@RestController
@RequestMapping("/extract")
public class DataExtractController {
@Autowired
private DataExtractService dataExtractService;
/**
*
*/
@ApiOperation("获取随机数据")
//@RequiresPermissions("dataTransform:extract:query")
@GetMapping("/getRandomData")
public Result<List<List<DataModel>>> getRandomData(RandomDataReq randomDataReq) {
return Result.success(dataExtractService.getRandomData(randomDataReq));
}
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.dataTransform.controller;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.dataTransform.domain.req.TestDataReq;
import com.ruoyi.dataTransform.service.EngineOperationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
*
* @ClassName EngineOperationController
* @Author
* @Date 2024/5/9 10:56
*/
@Api(tags = "引擎运行")
@RestController
@RequestMapping("/operation")
public class EngineOperationController {
@Autowired
private EngineOperationService engineOperationService;
/**
*
*/
@ApiOperation("测试引擎")
//@RequiresPermissions("dataTransform:operation:add")
@PostMapping("/testVersion")
public Result<Object> testVersion(@RequestBody TestDataReq testDataReq) {
return Result.success(engineOperationService.testVersion(testDataReq),"测试成功");
}
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.dataTransform.service;
import com.ruoyi.dataTransform.domain.req.RandomDataReq;
import com.ruoyi.ruleEngine.client.model.DataModel;
import java.util.List;
/**
* service
* @ClassName DataExtractService
* @Author
* @Date 2024/5/9 10:56
*/
public interface DataExtractService {
/**
*
* @param randomDataReq
* @return
*/
List<List<DataModel>> getRandomData(RandomDataReq randomDataReq);
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.dataTransform.service;
import com.ruoyi.dataTransform.domain.req.TestDataReq;
/**
* service
* @ClassName EngineOperationService
* @Author
* @Date 2024/5/9 10:56
*/
public interface EngineOperationService {
/**
*
* @param testDataReq
* @return
*/
Object testVersion(TestDataReq testDataReq);
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.dataTransform.service.impl;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.ruoyi.dataAsset.config.DruidDataSourceFactory;
import com.ruoyi.dataTransform.domain.req.RandomDataReq;
import com.ruoyi.dataTransform.service.DataExtractService;
import com.ruoyi.dataTransform.util.DataExtractUtil;
import com.ruoyi.ruleEngine.client.model.DataModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Service
*
* @author gtl
* @date 2024-04-20
*/
@Slf4j
@Service
public class DataExtractServiceImpl implements DataExtractService {
@Autowired
private DruidDataSourceFactory druidDataSourceFactory;
@Override
public List<List<DataModel>> getRandomData(RandomDataReq randomDataReq) {
DruidPooledConnection connection=null;
List<List<DataModel>> list=new ArrayList<>();
try {
// 获取数据源连接
connection = druidDataSourceFactory.get(randomDataReq.getDataSourceId()).getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
if(randomDataReq.getScope()==4){
// 数据模型
list.add(DataExtractUtil.getDataModels(connection,randomDataReq.getTableName()));
}else {
// 记录/数据集
list=DataExtractUtil.getRecordsModels(connection,randomDataReq.getTableName());
}
return list;
}
}

View File

@ -0,0 +1,88 @@
package com.ruoyi.dataTransform.service.impl;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.dataTransform.domain.req.TestDataReq;
import com.ruoyi.dataTransform.service.EngineOperationService;
import com.ruoyi.ruleEngine.client.config.RuleEngineVersionFactory;
import com.ruoyi.ruleEngine.client.context.DataModelContextHolder;
import com.ruoyi.ruleEngine.client.context.DataSetContextHolder;
import com.ruoyi.ruleEngine.client.context.RecordContextHolder;
import com.ruoyi.ruleEngine.client.dynamicLoad.DynamicLoader;
import com.ruoyi.ruleEngine.client.model.DataModel;
import com.ruoyi.ruleEngine.client.model.DataSetModel;
import com.ruoyi.ruleEngine.client.model.RecordModel;
import com.ruoyi.ruleEngine.client.model.process.DataModelProcessModel;
import com.ruoyi.ruleEngine.client.model.process.DataSetProcessModel;
import com.ruoyi.ruleEngine.client.model.process.RecordProcessModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Service
*
* @author gtl
* @date 2024-04-20
*/
@Slf4j
@Service
public class EngineOperationServiceImpl implements EngineOperationService {
@Autowired
private RuleEngineVersionFactory ruleEngineVersionFactory;
@Override
public Object testVersion(TestDataReq testDataReq) {
// 根据作用域编号放入对应的上下文中
switch (testDataReq.getScope()){
case 2: {
List<RecordModel> list=new ArrayList<>();
for (List<DataModel> dataModels : testDataReq.getRecordsList()) {
list.add(new RecordModel(dataModels));
}
// 创建数据集模型
DataSetModel dataSetModel = new DataSetModel(list);
// 将数据放入数据集上下文中
DataSetContextHolder.set(new DataSetProcessModel(dataSetModel));
}break;
case 3: {
// 创建记录模型
RecordModel recordModel = new RecordModel(testDataReq.getRecordsList().get(0));
// 将数据放入记录上下文中
RecordContextHolder.set(new RecordProcessModel(testDataReq.getKeys(),recordModel));
}break;
case 4: {
// 创建数据模型处理模型
DataModelProcessModel dataModelProcessModel = new DataModelProcessModel(testDataReq.getDataModel());
// 将数据放入模型上下文中
DataModelContextHolder.set(dataModelProcessModel);
}break;
default:throw new ServiceException("此作用域暂无法测试");
}
// 获取版本对应class文件的字节数组
Map<String, byte[]> bytecode = ruleEngineVersionFactory.get(testDataReq.getVersionId());
// 加载class文件到虚拟机中然后通过反射执行
@SuppressWarnings("resource")
DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(bytecode);
try {
Class<?> clazz = classLoader.loadClass(testDataReq.getVersionClass());
// 调用execution方法
Method mainMethod = clazz.getDeclaredMethod("execution");
mainMethod.invoke(clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("测试失败,"+e.getMessage());
}
// 处理后的测试数据
return switch (testDataReq.getScope()) {
case 2 -> DataSetContextHolder.get().getDataSetModel();
case 3 -> RecordContextHolder.get().getRecordModel();
case 4 -> DataModelContextHolder.get().getDataModel();
default -> null;
};
}
}

View File

@ -1,19 +0,0 @@
package com.ruoyi.dataTransform.controller;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
*
* @ClassName DataExtractController
* @Author
* @Date 2024/5/9 10:56
*/
@Api(tags = "数据抽取")
@RestController
@RequestMapping("/extract")
public class DataExtractController {
}

View File

@ -1,12 +0,0 @@
package com.ruoyi.dataTransform.service;
/**
* service
* @ClassName DataExtractService
* @Author
* @Date 2024/5/9 10:56
*/
public interface DataExtractService {
}

View File

@ -1,18 +0,0 @@
package com.ruoyi.dataTransform.service.impl;
import com.ruoyi.dataTransform.service.DataExtractService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* Service
*
* @author gtl
* @date 2024-04-20
*/
@Slf4j
@Service
public class DataExtractServiceImpl implements DataExtractService {
}

View File

@ -1,14 +1,17 @@
package com.ruoyi.ruleEngine.client.config;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.ruleEngine.constant.RuleOperationConstants;
import com.ruoyi.ruleEngine.domain.EngineVersion;
import com.ruoyi.ruleEngine.domain.req.EngineVersionQueryReq;
import com.ruoyi.ruleEngine.client.dynamicLoad.DynamicLoader;
import com.ruoyi.ruleEngine.remote.RemoteRuleEngineService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import java.util.List;
import java.util.Map;
/**
*
@ -22,13 +25,21 @@ public class RuleEngineApplicationRunner implements ApplicationRunner {
@Autowired
private RemoteRuleEngineService remoteRuleEngineService;
@Autowired
private RuleEngineVersionFactory ruleEngineVersionFactory;
@Override
public void run(ApplicationArguments args) throws Exception {
Result<List<EngineVersion>> result = remoteRuleEngineService.list(new EngineVersionQueryReq());
if(Result.isSuccess(result)){
log.info(result.getData());
}else {
log.error(result.getMsg());
result.getData().forEach(engineVersion -> {
// 获取版本内容
String content = engineVersion.getRuleContent().replaceAll("\r\n", "");
// 对source进行编译生成class文件存放在Map中这里用bytecode接收
Map<String, byte[]> bytecode = DynamicLoader.compile(engineVersion.getVersionClass() + RuleOperationConstants.FILE_SUFFIX,content );
// 存入工厂
ruleEngineVersionFactory.put(engineVersion.getId(), bytecode);
});
}
}
}

View File

@ -1,16 +0,0 @@
package com.ruoyi.ruleEngine.client.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
/**
*
* @ClassName RuleEngineClientConfig
* @Author
* @Date 2024/5/8 19:31
*/
@ComponentScan
@Import(RuleEngineApplicationRunner.class)
public class RuleEngineClientConfig {
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.ruleEngine.client.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import java.util.HashMap;
import java.util.Map;
/**
*
* @ClassName RuleEngineVersionFactory
* @Author
* @Date 2024/5/8 19:31
*/
@ComponentScan
@Import(RuleEngineApplicationRunner.class)
public class RuleEngineVersionFactory {
private final Map<Long,Map<String, byte[]>> versionContentMap=new HashMap<>();
public Map<Long, Map<String, byte[]>> getMap() {
return this.versionContentMap;
}
public void put(Long id,Map<String, byte[]> map) {
this.versionContentMap.put(id,map);
}
public Map<String, byte[]> get(Long id) {
return this.versionContentMap.get(id);
}
}

View File

@ -1,9 +1,10 @@
package com.ruoyi.ruleEngine.context;
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.model.process.DataModelProcessModel;
import com.ruoyi.ruleEngine.util.ScopeContextHolderUtil;
import com.ruoyi.ruleEngine.client.model.process.DataModelProcessModel;
import com.ruoyi.ruleEngine.client.util.ScopeContextHolderUtil;
import lombok.Data;
import lombok.experimental.SuperBuilder;
import java.sql.Connection;
/**

View File

@ -1,6 +1,6 @@
package com.ruoyi.ruleEngine.context;
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.model.process.DataSetProcessModel;
import com.ruoyi.ruleEngine.client.model.process.DataSetProcessModel;
import lombok.Data;
import lombok.experimental.SuperBuilder;

View File

@ -1,6 +1,6 @@
package com.ruoyi.ruleEngine.context;
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.model.process.RecordProcessModel;
import com.ruoyi.ruleEngine.client.model.process.RecordProcessModel;
import lombok.Data;
import lombok.experimental.SuperBuilder;

View File

@ -1,15 +1,15 @@
package com.ruoyi.ruleEngine.dynamicLoad;
package com.ruoyi.ruleEngine.client.dynamicLoad;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* @ClassName DynamicLoader

View File

@ -1,21 +1,11 @@
package com.ruoyi.ruleEngine.dynamicLoad;
package com.ruoyi.ruleEngine.client.dynamicLoad;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
/**
* .classmap
@ -108,7 +98,7 @@ public final class MemoryJavaFileManager extends ForwardingJavaFileManager {
@Override
public JavaFileObject getJavaFileForOutput(
JavaFileManager.Location location, String className,
Location location, String className,
JavaFileObject.Kind kind, FileObject sibling) throws IOException {
if (kind == JavaFileObject.Kind.CLASS) {
return new ClassOutputBuffer(className);

View File

@ -1,9 +1,9 @@
package com.ruoyi.ruleEngine.engine.scope;
package com.ruoyi.ruleEngine.client.engine.scope;
import com.ruoyi.ruleEngine.engine.Engine;
import com.ruoyi.ruleEngine.model.DataModel;
import com.ruoyi.ruleEngine.model.process.DataModelProcessModel;
import com.ruoyi.ruleEngine.context.DataModelContextHolder;
import com.ruoyi.ruleEngine.client.context.DataModelContextHolder;
import com.ruoyi.ruleEngine.client.engine.Engine;
import com.ruoyi.ruleEngine.client.model.DataModel;
import com.ruoyi.ruleEngine.client.model.process.DataModelProcessModel;
/**
*

View File

@ -1,10 +1,10 @@
package com.ruoyi.ruleEngine.engine.scope;
package com.ruoyi.ruleEngine.client.engine.scope;
import com.ruoyi.ruleEngine.context.DataSetContextHolder;
import com.ruoyi.ruleEngine.engine.Engine;
import com.ruoyi.ruleEngine.model.DataSetModel;
import com.ruoyi.ruleEngine.model.RecordModel;
import com.ruoyi.ruleEngine.model.process.DataSetProcessModel;
import com.ruoyi.ruleEngine.client.context.DataSetContextHolder;
import com.ruoyi.ruleEngine.client.engine.Engine;
import com.ruoyi.ruleEngine.client.model.DataSetModel;
import com.ruoyi.ruleEngine.client.model.RecordModel;
import com.ruoyi.ruleEngine.client.model.process.DataSetProcessModel;
import java.util.List;

View File

@ -1,10 +1,10 @@
package com.ruoyi.ruleEngine.engine.scope;
package com.ruoyi.ruleEngine.client.engine.scope;
import com.ruoyi.ruleEngine.context.RecordContextHolder;
import com.ruoyi.ruleEngine.engine.Engine;
import com.ruoyi.ruleEngine.model.DataModel;
import com.ruoyi.ruleEngine.model.RecordModel;
import com.ruoyi.ruleEngine.model.process.RecordProcessModel;
import com.ruoyi.ruleEngine.client.context.RecordContextHolder;
import com.ruoyi.ruleEngine.client.engine.Engine;
import com.ruoyi.ruleEngine.client.model.DataModel;
import com.ruoyi.ruleEngine.client.model.RecordModel;
import com.ruoyi.ruleEngine.client.model.process.RecordProcessModel;
import java.util.List;

View File

@ -1,4 +1,4 @@
package com.ruoyi.ruleEngine.model;
package com.ruoyi.ruleEngine.client.model;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,8 +1,9 @@
package com.ruoyi.ruleEngine.model;
package com.ruoyi.ruleEngine.client.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**

View File

@ -1,4 +1,4 @@
package com.ruoyi.ruleEngine.model;
package com.ruoyi.ruleEngine.client.model;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -1,7 +1,9 @@
package com.ruoyi.ruleEngine.model.process;
package com.ruoyi.ruleEngine.client.model.process;
import com.ruoyi.ruleEngine.model.DataModel;
import com.ruoyi.ruleEngine.client.model.DataModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
@ -10,6 +12,8 @@ import lombok.Data;
* @Date 2024/5/5 18:37
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DataModelProcessModel {
private DataModel dataModel;
}

View File

@ -1,6 +1,6 @@
package com.ruoyi.ruleEngine.model.process;
package com.ruoyi.ruleEngine.client.model.process;
import com.ruoyi.ruleEngine.model.DataSetModel;
import com.ruoyi.ruleEngine.client.model.DataSetModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

View File

@ -1,7 +1,10 @@
package com.ruoyi.ruleEngine.model.process;
package com.ruoyi.ruleEngine.client.model.process;
import com.ruoyi.ruleEngine.model.RecordModel;
import com.ruoyi.ruleEngine.client.model.RecordModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
@ -11,6 +14,8 @@ import java.util.List;
* @Date 2024/5/5 18:37
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RecordProcessModel {
private List<String> keys;
private RecordModel recordModel;

View File

@ -1,10 +1,10 @@
package com.ruoyi.ruleEngine.util;
package com.ruoyi.ruleEngine.client.util;
import com.ruoyi.ruleEngine.context.DataSetContextHolder;
import com.ruoyi.ruleEngine.model.DataModel;
import com.ruoyi.ruleEngine.model.DataSetModel;
import com.ruoyi.ruleEngine.model.RecordModel;
import com.ruoyi.ruleEngine.model.process.DataSetProcessModel;
import com.ruoyi.ruleEngine.client.context.DataSetContextHolder;
import com.ruoyi.ruleEngine.client.model.DataModel;
import com.ruoyi.ruleEngine.client.model.DataSetModel;
import com.ruoyi.ruleEngine.client.model.RecordModel;
import com.ruoyi.ruleEngine.client.model.process.DataSetProcessModel;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

View File

@ -1 +1 @@
com.ruoyi.ruleEngine.client.config.RuleEngineClientConfig
com.ruoyi.ruleEngine.client.config.RuleEngineVersionFactory

View File

@ -10,11 +10,11 @@ public class ConfigCodeConstants {
/**
*
*/
public final static String BASE_FILE_PATH="D:\\workspace\\gtl-ruoyi-server\\ruoyi-modules\\ruoyi-rule_engine\\ruoyi-rule_engine-common\\src\\main\\java\\com\\ruoyi\\ruleEngine\\context\\";
public final static String BASE_FILE_PATH="/file/";
/**
*
*/
public final static String[] CONFIG_FILE_NAME_ARRAY=new String[]{"engine_custom.txt","TaskContextHolder.java","DataSetContextHolder.java","RecordContextHolder.java","DataModelContextHolder.java"};
public final static String[] CONFIG_FILE_NAME_ARRAY=new String[]{"engine_custom.txt","TaskContextHolder.txt","DataSetContextHolder.txt","RecordContextHolder.txt","DataModelContextHolder.txt"};
/**
*
*/

View File

@ -7,16 +7,8 @@ package com.ruoyi.ruleEngine.constant;
* @Date 2024/5/4 16:12
*/
public class RuleOperationConstants {
/**
*
*/
public final static String CLASS_NAME="TestClass";
/**
*
*/
public final static String FILE_SUFFIX=".java";
/**
*
*/
public final static String METHOD_NAME="ruleTest";
}

View File

@ -1,23 +0,0 @@
package com.ruoyi.ruleEngine.domain.model;
import lombok.Data;
import java.util.List;
/**
*
* @ClassName TestData
* @Author
* @Date 2024/5/3 16:13
*/
@Data
public class TestData {
/**
*
*/
private Long id;
/**
*
*/
private List<String> list;
}

View File

@ -7,7 +7,6 @@ import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.ruleEngine.domain.EngineVersion;
import com.ruoyi.ruleEngine.domain.model.TestData;
import com.ruoyi.ruleEngine.domain.req.EngineVersionEditReq;
import com.ruoyi.ruleEngine.domain.req.EngineVersionQueryReq;
import com.ruoyi.ruleEngine.domain.req.EngineVersionSaveReq;
@ -55,16 +54,6 @@ public class EngineVersionController extends BaseController {
return Result.success(engineVersionService.createVersionClass(req));
}
/**
*
*/
@ApiOperation("测试引擎规则版本")
@RequiresPermissions("ruleEngine:version:add")
@PostMapping(value = "/test")
public Result<Object> ruleTest(@RequestBody TestData testData) {
return Result.success(engineVersionService.ruleTest(testData));
}
/**
*
*/

View File

@ -2,7 +2,6 @@ package com.ruoyi.ruleEngine.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.ruleEngine.domain.EngineVersion;
import com.ruoyi.ruleEngine.domain.model.TestData;
import com.ruoyi.ruleEngine.domain.req.VersionClassCreateReq;
import com.ruoyi.ruleEngine.domain.resp.VersionClassCreateResp;
import java.util.List;
@ -23,12 +22,6 @@ public interface EngineVersionService extends IService<EngineVersion> {
*/
public List<EngineVersion> list(EngineVersion engineConfig);
/**
*
* @param testData
*/
Object ruleTest(TestData testData);
/**
*
* @param req

View File

@ -4,8 +4,12 @@ import com.ruoyi.ruleEngine.constant.ConfigCodeConstants;
import com.ruoyi.ruleEngine.domain.resp.EngineConfigScopeResp;
import com.ruoyi.ruleEngine.service.EngineConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
@ -36,8 +40,9 @@ public class EngineConfigServiceImpl implements EngineConfigService {
index++;
continue;
}
String path=ConfigCodeConstants.BASE_FILE_PATH+scope;
String code = Files.readString(Paths.get(path));
ClassPathResource resource = new ClassPathResource(ConfigCodeConstants.BASE_FILE_PATH+scope);
InputStream inputStream = resource.getInputStream();
String code = IOUtils.toString(inputStream, String.valueOf(StandardCharsets.UTF_8));
String type=ConfigCodeConstants.CONFIG_FILE_TYPE_ARRAY[index++];
list.add(EngineConfigScopeResp.builder().type(type).name(scope).code(code).build());
}

View File

@ -2,25 +2,19 @@ package com.ruoyi.ruleEngine.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.ObjUtils;
import com.ruoyi.ruleEngine.constant.EngineVersionConstants;
import com.ruoyi.ruleEngine.constant.RuleOperationConstants;
import com.ruoyi.ruleEngine.domain.EngineVersion;
import com.ruoyi.ruleEngine.domain.model.TestData;
import com.ruoyi.ruleEngine.domain.req.VersionClassCreateReq;
import com.ruoyi.ruleEngine.domain.resp.EngineConfigScopeResp;
import com.ruoyi.ruleEngine.domain.resp.VersionClassCreateResp;
import com.ruoyi.ruleEngine.dynamicLoad.DynamicLoader;
import com.ruoyi.ruleEngine.mapper.EngineVersionMapper;
import com.ruoyi.ruleEngine.service.EngineConfigService;
import com.ruoyi.ruleEngine.service.EngineVersionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
/**
* Service
@ -65,35 +59,6 @@ public class EngineVersionServiceImpl extends ServiceImpl<EngineVersionMapper, E
return list(queryWrapper);
}
/**
*
* @param testData
*/
@Override
public Object ruleTest(TestData testData) {
Object invoke=null;
try {
EngineVersion config = this.getById(testData.getId());
String content = config.getRuleContent().replaceAll("\r\n", "");
// 对source进行编译生成class文件存放在Map中这里用bytecode接收
Map<String, byte[]> bytecode = DynamicLoader.compile(RuleOperationConstants.CLASS_NAME + RuleOperationConstants.FILE_SUFFIX,content );
// 加载class文件到虚拟机中然后通过反射执行
@SuppressWarnings("resource")
DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(
bytecode);
Class<?> clazz = classLoader.loadClass(RuleOperationConstants.CLASS_NAME);
// 调用ruleTest方法
Method mainMethod = clazz.getDeclaredMethod(RuleOperationConstants.METHOD_NAME, List.class);
invoke = mainMethod.invoke(null, testData.getList());
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException("测试失败");
}
return invoke;
}
/**
*
* @param req

View File

@ -0,0 +1,44 @@
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.client.model.process.DataModelProcessModel;
import com.ruoyi.ruleEngine.client.util.ScopeContextHolderUtil;
import lombok.Data;
import lombok.experimental.SuperBuilder;
import java.sql.Connection;
/**
* 数据模型上下文
* @ClassName DataModelContextHolder
* @Author 森静若林
*/
@Data
@SuperBuilder
public class DataModelContextHolder{
private static final ThreadLocal<DataModelProcessModel> THREAD_LOCAL=new ThreadLocal<>();
private RecordContextHolder recordContextHolder;
public static DataModelContextHolder build(RecordContextHolder recordContextHolder){
return DataModelContextHolder.builder()
.recordContextHolder(recordContextHolder)
.build();
}
public static DataModelProcessModel get() {
return THREAD_LOCAL.get();
}
public static void set(DataModelProcessModel dataModelProcessModel) {
THREAD_LOCAL.set(dataModelProcessModel);
}
public static void set(Connection connection,String sql){
ScopeContextHolderUtil.setDataSetContextHolder(connection,sql);
}
public static void remove() {
THREAD_LOCAL.remove();
}
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.client.model.process.DataSetProcessModel;
import lombok.Data;
import lombok.experimental.SuperBuilder;
/**
* 数据集上下文
* @ClassName DataSetContextHolder
* @Author 森静若林
*/
@Data
@SuperBuilder
public class DataSetContextHolder{
private static final ThreadLocal<DataSetProcessModel> THREAD_LOCAL=new ThreadLocal<>();
private TaskContextHolder taskContextHolder;
public static DataSetContextHolder build(TaskContextHolder taskContextHolder){
return DataSetContextHolder.builder()
.taskContextHolder(taskContextHolder)
.build();
}
public static DataSetProcessModel get() {
return THREAD_LOCAL.get();
}
public static void set(DataSetProcessModel dataSetProcessModel) {
THREAD_LOCAL.set(dataSetProcessModel);
}
public static void remove() {
THREAD_LOCAL.remove();
}
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.ruleEngine.client.context;
import com.ruoyi.ruleEngine.client.model.process.RecordProcessModel;
import lombok.Data;
import lombok.experimental.SuperBuilder;
/**
* 记录上下文
* @ClassName RecordContextHolder
* @Author 森静若林
*/
@Data
@SuperBuilder
public class RecordContextHolder{
private static final ThreadLocal<RecordProcessModel> THREAD_LOCAL=new ThreadLocal<>();
private DataSetContextHolder dataSetContextHolder;
public static RecordContextHolder build(DataSetContextHolder dataSetContextHolder){
return RecordContextHolder.builder()
.dataSetContextHolder(dataSetContextHolder)
.build();
}
public static RecordProcessModel get() {
return THREAD_LOCAL.get();
}
public static void set(RecordProcessModel recordProcessModel) {
THREAD_LOCAL.set(recordProcessModel);
}
public static void remove() {
THREAD_LOCAL.remove();
}
}

View File

@ -0,0 +1,13 @@
package com.ruoyi.ruleEngine.client.context;
/**
* 任务上下文
* @ClassName TaskContextHolder
* @Author 森静若林
*/
public class TaskContextHolder {
public static TaskContextHolder build(){
return new TaskContextHolder();
}
}

View File

@ -1,4 +1,4 @@
import com.ruoyi.dataAsset.engine.scope.scope_engine;
import com.ruoyi.ruleEngine.client.engine.scope.scope_engine;
/**
* 自定义引擎