初始化

master
面包骑士 2024-09-09 17:04:23 +08:00
commit 40fdd3147c
59 changed files with 3706 additions and 0 deletions

36
.gitignore vendored 100644
View File

@ -0,0 +1,36 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/
logs/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

15
Dockerfile 100644
View File

@ -0,0 +1,15 @@
FROM anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/dragonwell:17.0.4.0.4.8-standard-ga-8.6
#定义时区参数
ENV TZ=Asia/Shanghai
#设置时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone
VOLUME ["/home/logs/cloud-etl-server","/home/uploadPath"]
#拷贝执行jar包文件
COPY ./etl-rule-server/target/cloud-rule-engine.jar /home/app.jar
#构建启动命令
ENTRYPOINT ["java","-Dfile.encoding=utf-8","-jar","-Xbootclasspath/a:$toolspath/tools.jar"]
CMD ["/home/app.jar"]

View File

@ -0,0 +1,33 @@
<?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>cloud-rule-engine</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>etl-rule-common</artifactId>
<version>3.6.5</version>
<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>cloud-etl-common</artifactId>
<version>3.6.5</version>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,22 @@
package com.muyu.etl.rule.basic;
import com.muyu.etl.rule.basic.handler.BasicEngineHandler;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public interface BasicEngine<V> {
public void set(V value);
public V get();
public default void remove() {
BasicEngineHandler.remove();
}
public void execution();
}

View File

@ -0,0 +1,31 @@
package com.muyu.etl.rule.basic.abstracts;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.basic.BasicEngine;
import com.muyu.etl.rule.basic.handler.EngineRowHandler;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public abstract class DataEngineRowActuator implements BasicEngine<DataStructure[]> {
@Override
public void set(DataStructure[] values) {
EngineRowHandler.set(values);
}
@Override
public DataStructure[] get() {
return EngineRowHandler.get();
}
@Override
public void execution() {
this.run();
}
public abstract void run();
}

View File

@ -0,0 +1,31 @@
package com.muyu.etl.rule.basic.abstracts;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.basic.BasicEngine;
import com.muyu.etl.rule.basic.handler.EngineRowHandler;
import com.muyu.etl.rule.basic.handler.EngineRowsHandler;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public abstract class DataEngineRowsActuator implements BasicEngine<DataStructure[][]> {
@Override
public void set(DataStructure[][] values) {
EngineRowsHandler.set(values);
}
@Override
public DataStructure[][] get() {
return EngineRowsHandler.get();
}
@Override
public void execution() {
this.run();
}
public abstract void run();
}

View File

@ -0,0 +1,34 @@
package com.muyu.etl.rule.basic.abstracts;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.basic.BasicEngine;
import com.muyu.etl.rule.basic.handler.BasicEngineHandler;
import com.muyu.etl.rule.basic.handler.EngineValueHandler;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public abstract class DataEngineValueActuator implements BasicEngine<DataStructure> {
@Override
public void set(DataStructure dataStructure) {
EngineValueHandler.set(dataStructure);
}
@Override
public DataStructure get() {
return EngineValueHandler.get();
}
@Override
public void execution() {
this.run();
}
public abstract void run();
}

View File

@ -0,0 +1,24 @@
package com.muyu.etl.rule.basic.handler;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public class BasicEngineHandler {
private static final ThreadLocal<Object> threadLocal = new ThreadLocal<>();
public static void set(final Object handler) {
threadLocal.set(handler);
}
public static <T> T get() {
return (T) threadLocal.get();
}
public static void remove() {
}
}

View File

@ -0,0 +1,27 @@
package com.muyu.etl.rule.basic.handler;
import com.muyu.common.core.text.Convert;
import com.muyu.etl.domain.DataStructure;
import java.math.BigDecimal;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public class EngineRowHandler {
private static final ThreadLocal<DataStructure[]> threadLocal = new ThreadLocal<>();
public static void set(DataStructure[] dataStructureRow){
threadLocal.set(dataStructureRow);
}
public static DataStructure[] get(){
return threadLocal.get();
}
}

View File

@ -0,0 +1,23 @@
package com.muyu.etl.rule.basic.handler;
import com.muyu.etl.domain.DataStructure;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public class EngineRowsHandler {
private static final ThreadLocal<DataStructure[][]> threadLocal = new ThreadLocal<>();
public static void set(DataStructure[][] dataStructureRows){
threadLocal.set(dataStructureRows);
}
public static DataStructure[][] get(){
return threadLocal.get();
}
}

View File

@ -0,0 +1,56 @@
package com.muyu.etl.rule.basic.handler;
import com.muyu.common.core.text.Convert;
import com.muyu.etl.domain.DataStructure;
import java.math.BigDecimal;
import java.util.Date;
/**
* @Author WangXin
* @Data 2024/8/29
* @Description
* @Version 1.0.0
*/
public class EngineValueHandler {
public static void set(DataStructure dataStructure) {
BasicEngineHandler.set(dataStructure);
}
public static DataStructure get() {
return BasicEngineHandler.get();
}
public static Object getValue() {
return get().getValue();
}
public static Integer getIntValue() {
return Convert.toInt(getValue(), null);
}
public static Long getLongValue() {
return Convert.toLong(getValue(), null);
}
public static Float getFloatValue() {
return Convert.toFloat(getValue(), null);
}
public static Double getDoubleValue() {
return Convert.toDouble(getValue(), null);
}
public static Boolean getBooleanValue() {
return Convert.toBool(getValue(), null);
}
public static String getStringValue() {
return Convert.toStr(getValue(), null);
}
public static BigDecimal getBigDecimalValue() {
return Convert.toBigDecimal(getValue(), null);
}
}

View File

@ -0,0 +1,10 @@
package com.muyu.etl.rule.domain;
/**
* @Author WangXin
* @Data 2024/9/1
* @Description
* @Version 1.0.0
*/
public class DataStructureResp {
}

View File

@ -0,0 +1,82 @@
package com.muyu.etl.rule.domain;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.web.domain.BaseEntity;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
/**
* etl_rule_info
*
* @author WangXin
* @date 2024-08-25
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Setter
@Getter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("etl_rule_info")
public class RuleInfo extends BaseEntity{
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId( type = IdType.AUTO)
private Long id;
/** 规则名称 */
@Excel(name = "规则名称")
private String ruleName;
/** 规则编码 */
@Excel(name = "规则编码")
private String ruleCode;
/** 规则分类 */
@Excel(name = "规则分类")
private String ruleTypeValue;
/** 规则级别 */
@Excel(name = "规则级别")
private Long ruleLevelId;
/** 是否激活Y激活 N不激活 */
@Excel(name = "是否激活", readConverterExp = "Y=激活,N=不激活")
private String isActivation;
/** 规则状态(Y正常 N停用) */
@Excel(name = "规则状态(Y正常 N停用)")
private String status;
/** 规则说明 */
@Excel(name = "规则说明")
private String ruleExplain;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("ruleName", getRuleName())
.append("ruleCode", getRuleCode())
.append("ruleTypeValue", getRuleTypeValue())
.append("ruleLevelId", getRuleLevelId())
.append("isActivation", getIsActivation())
.append("status", getStatus())
.append("ruleExplain", getRuleExplain())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,93 @@
package com.muyu.etl.rule.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.muyu.common.core.annotation.Excel;
import com.muyu.common.core.web.domain.BaseEntity;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* etl_rule_version
*
* @author wangXin
* @date 2024-08-25
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Setter
@Getter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("etl_rule_version")
public class RuleVersion extends BaseEntity{
private static final long serialVersionUID = 1L;
/** 版本Id */
@TableId( type = IdType.AUTO)
private Long id;
/** 版本类 */
@Excel(name = "版本类")
private String ruleVersionClass;
/** 版本名称 */
@Excel(name = "版本名称")
private String ruleVersionName;
/** 版本CODE */
@Excel(name = "版本CODE")
private String ruleVersionCode;
/** 是否激活1激活 0未激活 */
@Excel(name = "是否激活", readConverterExp = "Y激活,N未激活")
private String ruleVersionIsActivation;
/** 是否测试0未测试 1测试已通过 2测试未通过 */
@Excel(name = "是否测试", readConverterExp = "0=未测试,1=测试已通过,2=测试未通过")
private Long ruleVersionIsTest;
/** 版本状态0初始化 1已发布 2未发布 */
@Excel(name = "版本状态", readConverterExp = "0=初始化,1=已发布,2=未发布")
private Long ruleVersionStatus;
/** 版本描述 */
@Excel(name = "版本描述")
private String ruleVersionDescribed;
/** 规则Id */
private Long ruleId;
/** 版本作用域 */
private Integer ruleVersionScope;
/**
*
*/
@TableField(exist = false)
private String classContent;
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("ruleVersionClass", getRuleVersionClass())
.append("ruleVersionName", getRuleVersionName())
.append("ruleVersionCode", getRuleVersionCode())
.append("ruleVersionIsActivation", getRuleVersionIsActivation())
.append("ruleVersionIsTest", getRuleVersionIsTest())
.append("ruleVersionStatus", getRuleVersionStatus())
.append("ruleVersionDescribed", getRuleVersionDescribed())
.append("ruleId", getRuleId())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,14 @@
package com.muyu.etl.rule.domain.constants;
/**
* @Author WangXin
* @Data 2024/9/9
* @Description
* @Version 1.0.0
*/
public interface RuleConstants {
String CLOUD_RULE_ENGINE = "cloud-rule-engine";
String RULE_VERSION_PATH = "ruleVersion";
}

View File

@ -0,0 +1,63 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @version 1.0
* @Author xie ya ru
* @Date 2024/8/19 19:14
* @
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Tag(name = "添加数据源信息" ,description = "数据源详细信息的添加")
public class DataSourceAddReq {
/**
*
*/
@NotEmpty(message = "数据来源不可为空")
@Schema(type = "String",defaultValue = "MySQL",description = "数据信息来源的信息名称")
private String databaseType;
/**
*
*/
@NotEmpty(message = "数据源名称不可为空")
@Schema(type = "String",defaultValue = "cloud-app",description = "数据源的来源的名称")
private String databaseFormName;
/**
*
*/
@NotEmpty(message = "数据来源地址不可为空")
@Schema(type = "String",defaultValue = "127.0.0.1",description = "数据来源地址")
private String databaseUrl;
/**
*
*/
@Schema(type = "String",defaultValue = "3306",description = "来源地址端口号")
private String databasePost;
/**
*
*/
@Schema(type = "String",defaultValue = "cloud-server",description = "数据库名称")
private String databaseName;
/**
*
*/
@Schema(type = "String",defaultValue = "root",description = "数据库登录名")
private String userName;
/**
*
*/
@Schema(type = "String",defaultValue = "wuzuxiaoniu@123.",description = "数据库登录密码")
private String userPwd;
}

View File

@ -0,0 +1,25 @@
package com.muyu.etl.rule.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @Author WangXin
* @Data 2024/9/2
* @Description
* @Version 1.0.0
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class DataSqlField {
private String columnName;
private String rowIndex;
}

View File

@ -0,0 +1,30 @@
package com.muyu.etl.rule.domain.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
/**
* @Author WangXin
* @Data 2024/9/2
* @Description
* @Version 1.0.0
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class DataTestReq {
private Long basicId;
private String tableName;
private String columnName;
private List<DataSqlField> rows;
}

View File

@ -0,0 +1,25 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author WangXin
* @Data 2024/8/24
* @Description
* @Version 1.0.0
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Tag(name = "启动规则引擎请求对象", description = "获取类的权限定名进行处理")
public class EtlRuleEngineReq {
@Schema(type = "String", defaultValue = "com.muyu.etl.rule.domain.req.DataSourceAddReq", description = "类的全限定名")
private String fullyQualifiedName;
}

View File

@ -0,0 +1,43 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description
* @Version 1.0.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Tag(name = "规则列表请求对象", description = "规则列表查询请求时所需要的条件")
public class EtlRuleListReq {
/**
*
*/
@Schema(type = "String", defaultValue = "邮箱规则", description = "规则名称模糊查询")
private String ruleName;
/**
*
*/
@Schema(type = "String", defaultValue = "email", description = "规则类型字典精确查询")
private String ruleTypeValue;
/**
*
*/
@Schema(type = "String", description = "是否激活字典查询 Y 或者 N", defaultValue = "Y")
private String isActivation;
/**
* Y N
*/
@Schema(type = "String", defaultValue = "Y", description = "规则开启和禁用的字段,Y或者N")
private String status;
}

View File

@ -0,0 +1,43 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description
* @Version 1.0.0
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Tag(name = "规则添加请求对象" ,description = "规则添加请求时所需要的条件")
public class EtlRuleSaveReq {
/** 规则名称 */
@Schema(type = "String", defaultValue = "not_null_rule", description = "定义唯一的规则名称",requiredProperties = "true")
private String ruleName;
/** 规则分类 */
@Schema(type = "Long", defaultValue = "1", description = "定义规则类型Id",requiredProperties = "true")
private Long ruleTypeId;
/** 规则说明 */
@Schema(type = "String", defaultValue = "非空校验", description = "规则描述",requiredProperties = "true")
private String ruleExplain;
/** 规则类权限定名 */
@Schema(type = "String", defaultValue = "com.muyu.etl.rule.domain.req.EtlRuleEngineReq", description = "规则所在类的全限定名",requiredProperties = "true")
private String fullyQualifiedName;
/** 是否公开(Y.公开 Y.不公开) */
@Schema(type = "String", defaultValue = "Y", description = "规则启动/停止",requiredProperties = "true")
private String status;
}

View File

@ -0,0 +1,34 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
/**
* @Author WangXin
* @Data 2024/8/27
* @Description
* @Version 1.0.0
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Tag(name = "执行规则请求对象", description = "执行规则请求所需的参数和类名")
public class ExecutionRuleVersionReq {
/**
*
*/
@Schema(description = "执行的类名", defaultValue = "engine_custom_email_IAW3S02", requiredProperties = "true")
private String engineKey;
/**
*
*/
@Schema(description = "执行方法所需的参数", requiredProperties = "true")
private HashMap<String, Object> params;
}

View File

@ -0,0 +1,37 @@
package com.muyu.etl.rule.domain.req;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author WangXin
* @Data 2024/8/27
* @Description
* @Version 1.0.0
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Tag(name = "文件写入请求对象", description = "编写规则类时写入文件进行持久化保存")
public class WriteFileReq {
/**
*
*/
@Schema(description = "存入的文件名", defaultValue = "engine_email-rule_JISID8S", requiredProperties = "true")
@NotEmpty(message = "文件名不能为空")
private String fileName;
/**
*
*/
@Schema(description = "存入的文件内容", defaultValue = "...", requiredProperties = "true")
@NotEmpty(message = "文件内容不能为空")
private String content;
}

View File

@ -0,0 +1,72 @@
package com.muyu.etl.rule.domain.resp;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.domain.RuleVersion;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
import java.util.function.Supplier;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description etl
* @Version 1.0.0
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Tag(name = "规则列表响应对象",description = "查询规则列表信息需要输出的字段")
public class EtlRuleListResp {
/** 主键 */
@Schema(type = "Long", defaultValue = "1", description = "规则主键",requiredProperties = "true")
private Long id;
/** 规则名称 */
@Schema(type = "String",defaultValue = "脱敏规则",description = "规则名称")
private String ruleName;
/** 规则编码 */
@Schema(type = "String",defaultValue = "tel_desensitization_rule",description = "规则名称")
private String ruleCode;
/** 规则分类 */
@Schema(type = "String",defaultValue = "system",description = "规则分类(字典字段)")
private String ruleTypeValue;
/** 规则说明 */
@Schema(type = "String",defaultValue = "对手机号进行脱敏处理",description = "规则说明")
private String ruleExplain;
/** 规则状态(Y正常 N停用) */
@Schema(type = "String",defaultValue = "Y",description = "规则状态(Y正常 N停用)")
private String status;
/** 规则级别 */
@Schema(type = "String",defaultValue = "",description = "规则级别")
private Long ruleLevelId;
/** 是否激活Y激活 N不激活 */
@Schema(type = "String",defaultValue = "N",description = "是否激活Y=激活,N=不激活)")
private String isActivation;
/** 规则版本列表 */
@Schema(type = "List", description = "规则版本列表")
private List<RuleVersion> ruleVersionList;
public static EtlRuleListResp buildEtlRuleListResp(RuleInfo ruleInfo, List<RuleVersion> list) {
return EtlRuleListResp.builder()
.id(ruleInfo.getId())
.ruleName(ruleInfo.getRuleName())
.ruleCode(ruleInfo.getRuleCode())
.ruleTypeValue(ruleInfo.getRuleTypeValue())
.ruleExplain(ruleInfo.getRuleExplain())
.status(ruleInfo.getStatus())
.ruleLevelId(ruleInfo.getRuleLevelId())
.isActivation(ruleInfo.getIsActivation())
.ruleVersionList(list)
.build();
}
}

View File

@ -0,0 +1,15 @@
package com.muyu.etl.rule.engine.bean.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface EngineParam {
/**
*
*/
public String name() default "";
}

View File

@ -0,0 +1,13 @@
package com.muyu.etl.rule.engine.bean.constant;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description
* @Version 1.0.0
*/
public interface FileConstants {
String JAVA_SUFFIX = ".java";
String CLASS_SUFFIX = ".class";
String FILE_DELIMITER = System.getProperty("os.name").contains("Windows") ? "\\" : "/";
}

View File

@ -0,0 +1,124 @@
package com.muyu.etl.rule.engine.core;
import com.muyu.etl.rule.engine.bean.annotation.EngineParam;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author WangXin
* @Data 2024/8/23
* @Descriptio
* @Version 1.0.0
*/
public class EngineContainer {
private static final Logger log = LogManager.getLogger(EngineContainer.class.getName());
public final static ConcurrentHashMap<String, Object> instanceMap = new ConcurrentHashMap<>(16);
private final static ConcurrentHashMap<String, Class<?>> classMap = new ConcurrentHashMap<>(16);
private final static ConcurrentHashMap<String, Method> methodMap = new ConcurrentHashMap<>(16);
private final static ConcurrentHashMap<String, List<String>> methodEngineParamMap = new ConcurrentHashMap<>(16);
public static void loadEngineInstance(String methodName, String engineKey, Class<?> aClass) {
Method method = findByMethodByClass(methodName, aClass);
List<String> engineParams = new ArrayList<>();
try {
instanceMap.put(engineKey, aClass.newInstance());
log.info("[{}]类实例化成功---》class:{}",engineKey,aClass.getName());
} catch (InstantiationException e) {
log.error("[类实例化错误]--- {}", e.getMessage(), e);
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
log.error("[类实例化错误]--- {}", e.getMessage(), e);
throw new RuntimeException(e);
}
classMap.put(engineKey, aClass);
methodMap.put(engineKey, method);
//获取方法所有参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
log.info("{}--》方法没有参数", methodName);
return;
}
//获取方法参数注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//获取参数
for (int i = 0; i < parameterTypes.length; i++) {
Annotation[] parameterAnnotation = parameterAnnotations[i];
if (parameterAnnotation.length == 0) {
log.error("请给所有参数添加注解");
throw new RuntimeException("请给所有参数添加注解");
}
if (parameterAnnotation.length > 1) {
log.error("参数只能有一个注解");
throw new RuntimeException("参数只能有一个注解");
}
EngineParam engineParam = null;
if (parameterAnnotation[0] instanceof EngineParam) {
engineParam = (EngineParam) parameterAnnotation[0];
}
if (engineParam == null) {
throw new RuntimeException("请使用EngineParam注解");
} else if (engineParam.name() != null && engineParam.name().isEmpty()) {
throw new RuntimeException("EnginParam注解的name参数不能为空");
}
engineParams.add(engineParam.name());
}
methodEngineParamMap.put(engineKey, engineParams);
log.info("初始化规则引擎成功---》规则引擎名称:{} ,执行方法:{},参数:{}", engineKey, method.getName(), engineParams.toString());
}
/**
*
*
* @param methodName
* @param aClass class
* @return method
*/
private static Method findByMethodByClass(String methodName, Class<?> aClass) {
Method method = null;
for (Method aMethod : aClass.getMethods()) {
if (aMethod.getName().equals(methodName)) {
method = aMethod;
}
}
if (method == null) {
log.info("[{}] 类中没有 [{}] 方法", aClass.getName(), methodName);
throw new RuntimeException("Method not found: " + methodName);
} else {
return method;
}
}
public static Object getInstance(String engineKey) {
return instanceMap.get(engineKey);
}
public static Method getMethodByClass(String engineKey) {
return methodMap.get(engineKey);
}
public static List<String> getMethodEngineParam(String engineKey) {
return methodEngineParamMap.get(engineKey);
}
public static Class<?> getClassByEngineKey(String engineKey) {
return classMap.get(engineKey);
}
}

View File

@ -0,0 +1,82 @@
package com.muyu.etl.rule.engine.core;
import com.muyu.etl.rule.engine.core.EngineContainer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @Author WangXin
* @Data 2024/8/23
* @Description
* @Version 1.0.0
*/
public class EngineExecution {
private static final Logger log = LogManager.getLogger(EngineExecution.class.getName());
/**
* method
* @param engineKey
* @param params
* @return
*/
public static Object argumentEngineExe(String engineKey, Map<String, Object> params){
Object instance = EngineContainer.getInstance(engineKey);
Method method = EngineContainer.getMethodByClass(engineKey);
List<String> methodEngineParam = EngineContainer.getMethodEngineParam(engineKey);
try {
int methodParamLength = methodEngineParam.size();
Object[] objects = new Object[methodParamLength];
for (int i = 0; i < methodParamLength; i++) {
objects[i] = params.get(methodEngineParam.get(i));
}
log.info("规则引擎 [{}] 调用参数 [{}]",engineKey, Arrays.toString(objects));
Object invoke = method.invoke(instance, objects);
log.info("规则引擎 [{}] 调用结果 [{}] ",engineKey, Arrays.toString(objects));
return invoke;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
/**
* method
* @param engineKey
* @return
*/
public static Object noArgumentEngineExe(String engineKey){
Object instance = EngineContainer.getInstance(engineKey);
Method method = EngineContainer.getMethodByClass(engineKey);
List<String> methodEngineParam = EngineContainer.getMethodEngineParam(engineKey);
int methodParamLength = methodEngineParam.size();
if (methodParamLength != 0){
log.info("[方法名错误] 此方法为有参方法请选择 [argumentEngineExe] 方法输入对应参数");
throw new RuntimeException("[方法名错误] 此方法为有参方法请选择 [argumentEngineExe] 方法输入对应参数");
}
try {
log.info("规则引擎 [{}] 启动",engineKey);
Object invoke = method.invoke(instance);
log.info("规则引擎 [{}] invoke 调用成功",engineKey);
return invoke;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,29 @@
package com.muyu.etl.rule.engine.core.classLoad;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* @Author WangXin
* @Data 2024/9/4
* @Description classloader
* @Version 1.0.0
*/
public class ExternalClassLoader extends URLClassLoader {
public ExternalClassLoader(URL[] urls) {
super(urls, Thread.currentThread().getContextClassLoader());
}
public Class<?> defineClassFromBytes(byte[] classBytes, String className) throws IOException {
return super.defineClass(className, classBytes, 0, classBytes.length);
}
public Class<?> loadClassFromPath(Path classFilePath, String className) throws IOException {
byte[] classData = Files.readAllBytes(classFilePath);
return defineClassFromBytes(classData, className);
}
}

View File

@ -0,0 +1,133 @@
package com.muyu.etl.rule.engine.core.classLoad;
import com.alibaba.fastjson2.JSON;
import com.muyu.etl.rule.engine.bean.constant.FileConstants;
import com.muyu.etl.rule.engine.util.FileLoadUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description java
* @Version 1.0.0
*/
public class JavaBinaryClassLoader extends ClassLoader {
private static final Logger log = LogManager.getLogger(JavaBinaryClassLoader.class.getName());
private static final JavaBinaryClassLoader loader = new JavaBinaryClassLoader();
/**
* class
*
* @param name
* @param pack
* @param locationFile
* @return class
*/
private static Class<?> loadClassByNameAndLocation(String name, String pack, File locationFile) {
//将class文件的数据读入到byte数组中
byte[] datas = loader.loadClassData(name, locationFile);
//通过byte数组加载Class对象
Class<?> aClass = loader.defineClass(pack + name, datas, 0, datas.length);
log.info("成功加载规则引擎 -- {}", aClass.getName());
return aClass;
}
/**
* @param pack com.muyu.bean.
* @param location
* @return
*/
public static Map<String, Class<?>> loadClassByLocation(String pack, String location) {
//列出所有的class文件
List<File> classFiles = FileLoadUtil.getClassFiles(location + FileConstants.FILE_DELIMITER + pack.replaceAll("\\.", FileConstants.FILE_DELIMITER));
log.info("class文件---->{}", JSON.toJSONString(classFiles));
HashMap<String, Class<?>> map = new HashMap<>();
classFiles.forEach(file -> {
String name = file.getName().substring(0, file.getName().lastIndexOf(FileConstants.CLASS_SUFFIX));
// Class<?> c = loadClassByNameAndLocation(name, pack + ".", new File(location+ FileConstants.FILE_DELIMITER +pack.replaceAll("\\.",FileConstants.FILE_DELIMITER)));
try {
log.info("转class对象请求入参---》name:{},pack:{}path:{}", name, pack, file.getAbsolutePath());
Class<?> value = urlLoadClassByNameAndLocation(name, pack, file.getAbsolutePath());
map.put(name, value);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
return map;
}
/**
*
*
* @param name
* @param locationFile
* @return
*/
public byte[] loadClassData(String name, File locationFile) {
byte[] byteArray = null;
try {
FileInputStream fis = new FileInputStream(locationFile + FileConstants.FILE_DELIMITER + name + FileConstants.CLASS_SUFFIX);
// 创建ByteArrayOutputStream对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 创建一个缓冲区
byte[] buffer = new byte[1024];
int length;
// 读取文件内容并写入缓冲区
while ((length = fis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
// 将缓冲区中的内容转换为byte数组
byteArray = bos.toByteArray();
} catch (IOException e) {
log.error("[【{}】文件转换成字节数组错误]{}", name, e.getMessage(), e);
throw new RuntimeException(e);
}
return byteArray;
}
/**
* class
*
* @param name
* @param pack
* @param path
* @return class
*/
private static Class<?> urlLoadClassByNameAndLocation(String name, String pack, String path) throws IOException {
Path classFilePath = Paths.get(path);
URL[] urls = new URL[]{new File(path).toURI().toURL()};
ExternalClassLoader externalClassLoader = new ExternalClassLoader(urls);
// 注意类名必须是完全限定名(包括包名)
log.info("[externalClassLoader]请求入参---》classPath:{},className:{}", classFilePath, pack + "." + name);
Class<?> clazz = externalClassLoader.loadClassFromPath(classFilePath, pack + "." + name);
return clazz;
}
public static void main(String[] args) {
File file = new File("D:\\idea_data\\ETL\\RuleEngine\\src\\main\\java\\com\\muyu\\engine\\core\\classLoad\\ExternalClassLoader.java");
String path = file.getPath();
String absolutePath = file.getAbsolutePath();
System.out.println(path);
System.out.println(absolutePath.substring(0, absolutePath.lastIndexOf(FileConstants.CLASS_SUFFIX)));
}
}

View File

@ -0,0 +1,106 @@
package com.muyu.etl.rule.engine.core.complier;
import com.muyu.etl.rule.engine.bean.constant.FileConstants;
import com.muyu.etl.rule.engine.util.FileLoadUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.util.Arrays;
import java.util.List;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description java
* @Version 1.0.0
*/
public class SourceCodeCompiler {
private static final Logger log = LogManager.getLogger(SourceCodeCompiler.class.getName());
/**
* java
*/
private static JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
/**
* java
*/
private static StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
private final static String workPath = System.getProperty("user.dir");
/**
*
*
* @param path
*/
public static void javaCompilerPath(String path) {
List<File> javaFiles = FileLoadUtil.getJavaFiles(path);
File[] array = javaFiles.toArray(new File[javaFiles.size()]);
javaCompiler(path, array);
}
public static void javaCompilerFile(String... filePath) {
int filePathLength = filePath.length;
File[] files = new File[filePathLength];
for (int i = 0; i < filePathLength; i++) {
files[i] = new File(filePath[i]);
}
javaCompiler("filePath", files);
}
/**
* java
*
* @param file
*/
public static void javaCompiler(String path, File... file) {
//通过源文件获取到要编译的Java源代码迭代器包括所有内部类其中每个类都是一个JavaFileObject,也被称为一个汇编单元
// 使用文件对象管理器来获取文件
Iterable<? extends JavaFileObject> javaFileObjects = fileManager.getJavaFileObjects(file);
//生成编译任务
log.info("程序运行地址为: {}", path);
List<String> options = Arrays.asList("-classpath", path, "-verbose", "-d", path);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, javaFileObjects);
//执行编译任务
Boolean call = task.call();
if (call) {
log.info("[{}个文件编译成功]", file.length);
} else {
throw new RuntimeException("[{}文件编译失败] Compilation failed");
}
}
/**
* java
*/
public static void javaCompiler(String classConfigPath, String classpath, String javaPath, String engineKey) {
//通过源文件获取到要编译的Java源代码迭代器包括所有内部类其中每个类都是一个JavaFileObject,也被称为一个汇编单元
// 使用文件对象管理器来获取文件
log.info("[开始编译] 请求参数 -----》 classConfigPath{} --- classpath:{} --- javaPath:{} --- engineKey:{}", classConfigPath, classpath, javaPath, engineKey);
String javaFilePath = javaPath + FileConstants.FILE_DELIMITER + engineKey + FileConstants.JAVA_SUFFIX;
log.info("[java文件路径] ---> {}}", javaFilePath);
// 构建编译参数数组
String[] options = {
"-classpath", classConfigPath,
"-verbose",
"-d", classpath,
javaFilePath
};
log.info("[构建编译参数数组成功] ---> {}}", Arrays.toString(options));
// 创建编译任务
int run = compiler.run(null, null, null, options);
// 关闭文件管理器
if (run==0) {
log.info("[文件编译成功]");
} else {
throw new RuntimeException(String.format("[{}文件编译失败] Compilation failed",engineKey));
}
}
}

View File

@ -0,0 +1,197 @@
package com.muyu.etl.rule.engine.util;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.etl.rule.engine.bean.constant.FileConstants;
import com.muyu.etl.rule.engine.core.complier.SourceCodeCompiler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.util.Arrays;
import java.util.List;
/**
* @Author WangXin
* @Data 2024/8/22
* @Description
* @Version 1.0.0
*/
public class FileLoadUtil {
private static final Logger log = LogManager.getLogger(SourceCodeCompiler.class.getName());
/**
*
*
* @param file
* @return
*/
public static File isFilePresence(File file) {
if (file.exists()) {
return file;
}
log.error("[文件路径错误]");
throw new RuntimeException("[文件路径错误]");
}
public static File[] isFilesExist(File[] files) {
if (files == null || files.length == 0) {
log.error("该文件夹下没有文件,请创建文件");
throw new RuntimeException("该文件夹下没有文件,请创建文件");
}
return files;
}
/**
*
*
* @param folderPath
* @return java
*/
public static List<File> getJavaFiles(String folderPath) {
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdirs();
}
File[] files = folder.listFiles();
return Arrays.stream(isFilesExist(files)).filter(FileLoadUtil::isFileType).toList();
}
/**
*
*
* @param folderPath
* @return class
*/
public static List<File> getClassFiles(String folderPath) {
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdirs();
}
File[] files = folder.listFiles();
List<File> list = Arrays.stream(isFilesExist(files)).filter(FileLoadUtil::isClassFileType).toList();
log.info("[{}]路劲下的class文件有[{}]", folderPath, JSONObject.toJSONString(list));
return list;
}
/**
* java
*
* @param file
* @return
*/
public static Boolean isFileType(File file) {
return file.getName().endsWith(FileConstants.JAVA_SUFFIX);
}
/**
* class
*
* @param file
* @return
*/
public static Boolean isClassFileType(File file) {
return file.getName().endsWith(FileConstants.CLASS_SUFFIX);
}
/**
* java
*/
public static File createJavaFile(String filePath, String fileName) {
filePath = filePath + FileConstants.FILE_DELIMITER + fileName.split("_")[0];
File file = new File(filePath);
if (!(file.exists() && file.isDirectory())) {
log.info("创建的文件夹:{}", filePath);
//创建文件夹
boolean mkdirs = file.mkdirs();
log.info("创建文件夹{}", mkdirs ? "成功" : "失败");
}
filePath = filePath + FileConstants.FILE_DELIMITER + fileName + FileConstants.JAVA_SUFFIX;
File classFile = new File(filePath);
if (!(classFile.exists() && classFile.isFile())) {
try {
log.info("创建的文件:{}", filePath);
boolean newFile = classFile.createNewFile();
log.info("创建文件{}", newFile ? "成功" : "失败");
} catch (IOException e) {
log.error("创建 [{}] 文件失败 --> {}", fileName, e.getMessage(), e);
throw new RuntimeException(e);
}
}
return classFile;
}
/**
*
*/
public static void writeFile(String filePath, String fileName, String content) {
log.info("写文件 ---> 入参:[filePath:{},fileName:{},content{}]", filePath, fileName, content);
File javaFile = createJavaFile(filePath, fileName);
try {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(javaFile));
bufferedWriter.write(content);
bufferedWriter.flush();
bufferedWriter.close();
} catch (IOException e) {
log.error("保存[{}]文件失败 ---> {}", fileName, e.getMessage(), e);
throw new RuntimeException(e);
}
}
/**
*
*/
public static String readFile(String filePath, String fileName) {
try {
File file = new File(filePath + FileConstants.FILE_DELIMITER + fileName.split("_")[0] + FileConstants.FILE_DELIMITER + fileName + FileConstants.JAVA_SUFFIX);
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String content = "";
String len;
while ((len = bufferedReader.readLine()) != null) {
content += len + "\n";
}
return content;
} catch (Exception e) {
log.error("读取[{}]文件失败 ---> {}", fileName, e.getMessage(), e);
return "";
}
}
public static void main(String[] args) {
String str = "package com.muyu.rule.test;\n" +
"\n" +
"import com.muyu.etl.rule.engine.bean.annotation.EngineParam;\n" +
"import org.apache.logging.log4j.LogManager;\n" +
"import org.apache.logging.log4j.Logger;\n" +
"\n" +
"/**\n" +
" * @Author WangXin\n" +
" * @Data 2024/8/23\n" +
" * @Description\n" +
" * @Version 1.0.0\n" +
" */\n" +
"public class XieYaRu {\n" +
"\n" +
" private static final Logger log = LogManager.getLogger(XieYaRu.class.getName());\n" +
"\n" +
" public String test(@EngineParam(name = \"phone\") String phone,@EngineParam(name = \"pat\") String pat){\n" +
" log.info(\"程序入参phone -> {} ,pat -> {}\",phone,pat);\n" +
" if (phone.matches(pat)){\n" +
" return phone;\n" +
" }else {\n" +
" throw new RuntimeException(\"手机号格式错误\");\n" +
" }\n" +
"\n" +
" }\n" +
"}";
writeFile("C:\\Users\\wx\\Desktop\\测试", "XieYaRu", str);
String xieYaRu = readFile("C:\\Users\\wx\\Desktop\\测试", "XieYaRu");
System.out.println(xieYaRu);
}
}

View File

@ -0,0 +1,54 @@
package com.muyu.etl.rule.engine.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
/**
* @ClassName: PropertiesUtil
* @Description:
* @author: wangXin
* @date: 2024/6/18 19:45
* @Version 1.0.0
*/
public class PropertiesUtil {
private static final Properties props = new Properties();
private static final Map<String, String> PROPER_MAP = new ConcurrentHashMap<>();
static {
InputStream is = null;
try {
is = PropertiesUtil.class.getClassLoader().getResourceAsStream("application.properties");
props.load(is);
Iterator<Object> iterator = props.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
PROPER_MAP.put(key, props.getProperty(key));
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
public static String getProperty(String key) {
return PROPER_MAP.get(key);
}
public static void main(String[] args) {
System.out.println(getProperty("db.username"));
}
}

View File

@ -0,0 +1,38 @@
package com.muyu.etl.rule.util;
import com.muyu.etl.rule.basic.BasicEngine;
import com.muyu.etl.rule.basic.abstracts.DataEngineValueActuator;
/**
* @Author WangXin
* @Data 2024/8/24
* @Description
* @Version 1.0.0
*/
public class EnginePackUtil {
/**
*
* @param fullyQualifiedName
* @return
*/
public static String getEnginePack(String fullyQualifiedName) {
return fullyQualifiedName.substring(0,fullyQualifiedName.lastIndexOf("."));
}
/**
*
* @param fullyQualifiedName
* @return
*/
public static String getEngineClass(String fullyQualifiedName) {
return fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf(".") + 1);
}
public static void main(String[] args) {
String enginePack = getEnginePack("com.muyu.etl.rule.domain.req.DataSourceAddReq");
System.out.println(enginePack);
String engineClass = getEngineClass("com.muyu.etl.rule.domain.req.DataSourceAddReq");
System.out.println(engineClass);
}
}

View File

@ -0,0 +1,29 @@
<?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>cloud-rule-engine</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>etl-rule-remote</artifactId>
<version>3.6.5</version>
<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>etl-rule-common</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
package com.muyu.etl.rule.remote;
import com.muyu.common.core.domain.Result;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.domain.constants.RuleConstants;
import com.muyu.etl.rule.remote.factory.RemoteRuleVersionBackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* @version 1.0
* @Author xie ya ru
* @Date 2024/9/2 14:35
* @
*/
@FeignClient(contextId = "remoteRuleVersion",
value = RuleConstants.CLOUD_RULE_ENGINE,
path = RuleConstants.RULE_VERSION_PATH,
fallbackFactory = RemoteRuleVersionBackFactory.class)
public interface RemoteRuleVersion {
@PostMapping("/groupFile/{engineKey}")
public Result<DataStructure[][]> executionGroupRuleVersion(@PathVariable("engineKey") String engineKey, @RequestBody DataStructure[][] dataStructureRows);
}

View File

@ -0,0 +1,32 @@
package com.muyu.etl.rule.remote.factory;
import com.muyu.common.core.domain.Result;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.remote.RemoteRuleVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* @version 1.0
* @Author xie ya ru
* @Date 2024/9/1 10:04
* @
*/
@Component
public class RemoteRuleVersionBackFactory implements FallbackFactory<RemoteRuleVersion> {
private static final Logger log = LoggerFactory.getLogger(RemoteRuleVersionBackFactory.class);
@Override
public RemoteRuleVersion create(Throwable cause) {
log.error("文件服务调用失败:{}", cause.getMessage());
return new RemoteRuleVersion() {
@Override
public Result<DataStructure[][]> executionGroupRuleVersion(String engineKey, DataStructure[][] dataStructureRows) {
return Result.error("查询数据失败:"+cause.getMessage());
}
};
}
}

View File

@ -0,0 +1 @@
com.muyu.etl.rule.remote.factory.RemoteRuleVersionBackFactory

View File

@ -0,0 +1,128 @@
<?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>cloud-rule-engine</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>etl-rule-server</artifactId>
<version>3.6.5</version>
<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>cloud-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>etl-datasource-remote</artifactId>
<version>3.6.5</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>
<!-- Mysql Connector -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- MuYu Common DataSource -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datasource</artifactId>
</dependency>
<!-- MuYu Common DataScope -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-datascope</artifactId>
</dependency>
<!-- MuYu Common Log -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-log</artifactId>
</dependency>
<!-- XllJob定时任务 -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>cloud-common-xxl</artifactId>
</dependency>
<dependency>
<groupId>com.muyu</groupId>
<artifactId>etl-rule-common</artifactId>
<version>3.6.5</version>
</dependency>
</dependencies>
<build>
<finalName>cloud-rule-engine</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.6</version>
<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>
<version>3.1.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,33 @@
package com.muyu.etl.rule;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.basic.abstracts.DataEngineRowsActuator;
import com.muyu.etl.rule.operation.ArrayUtil;
import java.util.Arrays;
import java.util.List;
/**
* @Author WangXin
* @Data Mon Sep 09 2024 01:04:05 GMT+0800 ()
* @Description null
* @Version 1.0.0
*/
public class ENGINE_NOT_NULL_NAME_V1 extends DataEngineRowsActuator {
@Override
public void run() {
DataStructure[][] dataStructuresList = get();
ArrayUtil<DataStructure[]> arrayUtil = new ArrayUtil<>(dataStructuresList);
while (arrayUtil.hasNext()){
DataStructure[] dataStructures = arrayUtil.next();
List<DataStructure> dataStructureList = Arrays.stream(dataStructures).filter(dataStructure -> dataStructure.getKey().equals("name") && dataStructure.getValue() == null).toList();
if (dataStructureList.size() > 0){
arrayUtil.remove();
}
}
set(arrayUtil.getCurrentArray());
}
}

View File

@ -0,0 +1,17 @@
package com.muyu.etl.rule;
import com.muyu.common.security.annotation.EnableCustomConfig;
import com.muyu.common.security.annotation.EnableMyFeignClients;
import groovy.util.logging.Log4j2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Log4j2
@EnableCustomConfig
@EnableMyFeignClients
@SpringBootApplication
public class EtlRuleEngineApplication {
public static void main(String[] args) {
SpringApplication.run(EtlRuleEngineApplication.class, args);
}
}

View File

@ -0,0 +1,52 @@
package com.muyu.etl.rule.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author WangXin
* @Data 2024/8/27
* @Description
* @Version 1.0.0
*/
@Configuration
@ConfigurationProperties(prefix = "engine")
@Data
public class EngineConfig {
//执行方法名
public String methodName;
//操作地址
public String sourceLocation;
//编译地址
public String classConfigPath;
//包名
public String packageName;
//window地址源地址
public String windowSourceLocation;
//linux源地址
public String linuxSourceLocation;
//window class文件配置地址
public String windowsClassConfigPath;
//linux class文件配置地址
public String linuxClassConfigPath;
@Bean
public EngineConfig initengineConfig() {
//获取系统
String osName = System.getProperty("os.name");
if (osName.contains("Windows")) {
sourceLocation = windowSourceLocation;
classConfigPath = windowsClassConfigPath;
} else if (osName.contains("Linux")) {
sourceLocation = linuxSourceLocation;
classConfigPath = linuxClassConfigPath;
} else {
throw new RuntimeException("暂无该系统");
}
return new EngineConfig();
}
}

View File

@ -0,0 +1,125 @@
package com.muyu.etl.rule.controller;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.poi.ExcelUtil;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.web.page.TableDataInfo;
import com.muyu.common.security.annotation.RequiresPermissions;
import com.muyu.common.security.utils.SecurityUtils;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.domain.req.EtlRuleListReq;
import com.muyu.etl.rule.domain.resp.EtlRuleListResp;
import com.muyu.etl.rule.service.IRuleInfoService;
import com.muyu.etl.rule.service.IRuleVersionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
* @Author WangXin
* @Data ${date}
* @Description
* @Version 1.0.0
*/
@RestController
@RequestMapping("/ruleInfo")
@Tag(name = "规则维护", description = "规则维护控制层")
@Log4j2
public class RuleInfoController extends BaseController {
@Resource
private IRuleInfoService ruleInfoService;
@Resource
private IRuleVersionService ruleVersionService;
/**
*
*/
@RequiresPermissions("engine:ruleInfo:list")
@PostMapping("/list")
@Operation(summary = "查询规则维护列表", description = "根据规则维护请求参数查询规则维护列表")
public Result<TableDataInfo<EtlRuleListResp>> list(@RequestBody EtlRuleListReq ruleInfoReq) {
startPage();
List<RuleInfo> list = ruleInfoService.selectRuleInfoList(ruleInfoReq);
log.info("数据总条数---》{}条", list.size());
return getDataTable(
list.stream()
.map(ruleInfo -> EtlRuleListResp.buildEtlRuleListResp(
ruleInfo, ruleVersionService.selectRuleVersionListByRuleId(ruleInfo.getId())
))
.toList()
);
}
/**
*
*/
@RequiresPermissions("engine:ruleInfo:export")
@PostMapping("/export")
@Operation(summary = "导出规则维护列表", description = "根据规则维护请求参数导出规则维护列表")
public void export(HttpServletResponse response, @RequestBody EtlRuleListReq ruleInfoReq) {
List<RuleInfo> list = ruleInfoService.selectRuleInfoList(ruleInfoReq);
ExcelUtil<RuleInfo> util = new ExcelUtil<RuleInfo>(RuleInfo.class);
util.exportExcel(response, list, "规则维护数据");
}
/**
*
*/
@RequiresPermissions("engine:ruleInfo:query")
@GetMapping(value = "/{id}")
@Operation(summary = "获取规则维护详细信息", description = "根据规则维护id获取规则维护详细信息")
public Result<EtlRuleListResp> getInfo(@PathVariable("id") Long id) {
return success(EtlRuleListResp.buildEtlRuleListResp(
ruleInfoService.selectRuleInfoById(id),
ruleVersionService.selectRuleVersionListByRuleId(id)
));
}
/**
*
*/
@RequiresPermissions("engine:ruleInfo:add")
@PostMapping
@Operation(summary = "新增规则维护", description = "根据规则维护请求参数新增规则维护")
public Result<Integer> add(
@Validated @RequestBody RuleInfo ruleInfo) {
if (ruleInfoService.checkIdUnique(ruleInfo)) {
return error("新增 规则维护 '" + ruleInfo + "'失败,规则维护已存在");
}
ruleInfo.setCreateBy(SecurityUtils.getUsername());
return toAjax(ruleInfoService.save(ruleInfo));
}
/**
*
*/
@RequiresPermissions("engine:ruleInfo:edit")
@PutMapping
@Operation(summary = "修改规则维护", description = "根据规则维护Id修改规则维护")
public Result<Integer> edit(
@Validated @RequestBody RuleInfo ruleInfo) {
if (!ruleInfoService.checkIdUnique(ruleInfo)) {
return error("修改 规则维护 '" + ruleInfo + "'失败,规则维护不存在");
}
ruleInfo.setUpdateBy(SecurityUtils.getUsername());
return toAjax(ruleInfoService.updateById(ruleInfo));
}
/**
*
*/
@RequiresPermissions("engine:ruleInfo:remove")
@DeleteMapping("/{ids}")
@Operation(summary = "删除规则维护", description = "根据规则维护Id删除规则维护")
public Result<Integer> remove(@PathVariable("ids") Long[] ids) {
ruleInfoService.removeBatchByIds(Arrays.asList(ids));
return success();
}
}

View File

@ -0,0 +1,266 @@
package com.muyu.etl.rule.controller;
import java.util.Arrays;
import java.util.List;
import com.dtflys.forest.annotation.Post;
import com.muyu.etl.data.access.domain.DataAnalysis;
import com.muyu.etl.data.access.domain.resp.TableInfoResp;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.domain.req.DataTestReq;
import com.muyu.etl.rule.domain.req.ExecutionRuleVersionReq;
import com.muyu.etl.rule.domain.req.WriteFileReq;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import javax.annotation.Resource;
import org.apache.commons.codec.language.bm.RuleType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.muyu.common.security.annotation.RequiresPermissions;
import com.muyu.etl.rule.domain.RuleVersion;
import com.muyu.etl.rule.service.IRuleVersionService;
import com.muyu.common.core.web.controller.BaseController;
import com.muyu.common.core.domain.Result;
import com.muyu.common.core.utils.poi.ExcelUtil;
import com.muyu.common.security.utils.SecurityUtils;
import org.springframework.validation.annotation.Validated;
import com.muyu.common.core.web.page.TableDataInfo;
/**
* @Author wangXin
* @Data ${date}
* @Description
* @Version 1.0.0
*/
@RestController
@RequestMapping("/ruleVersion")
@Tag(name = "规则版本", description = "规则版本控制层")
public class RuleVersionController extends BaseController {
@Resource
private IRuleVersionService ruleVersionService;
/**
*
*/
@RequiresPermissions("engine:ruleVersion:list")
@PostMapping("/list")
@Operation(summary = "查询规则版本列表", description = "根据规则版本请求参数查询规则版本列表")
public Result<TableDataInfo<RuleVersion>> list(@RequestBody RuleVersion ruleVersion) {
startPage();
List<RuleVersion> list = ruleVersionService.selectRuleVersionList(ruleVersion);
return getDataTable(list);
}
/**
*
*/
@RequiresPermissions("engine:ruleVersion:export")
@PostMapping("/export")
@Operation(summary = "导出规则版本列表", description = "根据规则版本请求参数导出规则版本列表")
public void export(HttpServletResponse response, @RequestBody RuleVersion ruleVersion) {
List<RuleVersion> list = ruleVersionService.selectRuleVersionList(ruleVersion);
ExcelUtil<RuleVersion> util = new ExcelUtil<RuleVersion>(RuleVersion.class);
util.exportExcel(response, list, "规则版本数据");
}
/**
*
*/
@RequiresPermissions("engine:ruleVersion:query")
@GetMapping(value = "/{id}")
@Operation(summary = "获取规则版本详细信息", description = "根据规则版本id获取规则版本详细信息")
public Result<List<RuleVersion>> getInfo(@PathVariable("id") Long id) {
return success(ruleVersionService.selectRuleVersionById(id));
}
/**
*
*/
@RequiresPermissions("engine:ruleVersion:add")
@PostMapping
@Operation(summary = "新增规则版本", description = "根据规则版本请求参数新增规则版本")
@Transactional(rollbackFor = Exception.class)
public Result<Integer> add(
@Validated @RequestBody RuleVersion ruleVersion) {
if (ruleVersionService.checkIdUnique(ruleVersion)) {
return error("新增 规则版本 '" + ruleVersion + "'失败,规则版本已存在");
}
ruleVersion.setCreateBy(SecurityUtils.getUsername());
boolean save = ruleVersionService.save(ruleVersion);
if (save) {
this.writeFile(
WriteFileReq.builder()
.fileName(ruleVersion.getRuleVersionClass())
.content(ruleVersion.getClassContent())
.build()
);
}
return toAjax(save);
}
/**
*
*/
@RequiresPermissions("engine:ruleVersion:edit")
@PutMapping
@Operation(summary = "修改规则版本", description = "根据规则版本Id修改规则版本")
public Result<Integer> edit(
@Validated @RequestBody RuleVersion ruleVersion) {
if (!ruleVersionService.checkIdUnique(ruleVersion)) {
return error("修改 规则版本 '" + ruleVersion + "'失败,规则版本不存在");
}
ruleVersion.setUpdateBy(SecurityUtils.getUsername());
return toAjax(ruleVersionService.updateById(ruleVersion));
}
/**
*
*/
@RequiresPermissions("engine:ruleVersion:remove")
@DeleteMapping("/{ids}")
@Operation(summary = "删除规则版本", description = "根据规则版本Id删除规则版本")
public Result<Integer> remove(@PathVariable("ids") Long[] ids) {
ruleVersionService.removeBatchByIds(Arrays.asList(ids));
return success();
}
/**
*
*
* @param fileName
* @return
*/
@RequiresPermissions("engine:ruleVersion:readFile")
@PostMapping("/readFile/{fileName}")
@Operation(summary = "根据文件名称读取文件内容", description = "根据文件名称读取文件内容")
public Result<String> readFile(@PathVariable("fileName") String fileName) {
return Result.success(ruleVersionService.readFile(fileName));
}
/**
*
*
* @param writeFileReq
* @return
*/
@RequiresPermissions("engine:ruleVersion:writeFile")
@PostMapping("/writeFile")
@Operation(summary = "根据文件名称写入文件内容", description = "根据文件名称写入文件内容")
public Result<?> writeFile(@RequestBody WriteFileReq writeFileReq) {
ruleVersionService.writeFile(writeFileReq);
return Result.success();
}
/**
* java
*/
@RequiresPermissions("engine:ruleVersion:execution")
@PostMapping("/execution")
@Operation(summary = "执行java文件", description = "执行java文件")
public Result<?> executionRuleVersion(@RequestBody ExecutionRuleVersionReq executionRuleVersionReq) {
return Result.success(ruleVersionService.executionRuleVersion(executionRuleVersionReq));
}
/**
* java
*/
@RequiresPermissions("engine:ruleVersion:execution")
@PostMapping("/execution/{engineKey}")
@Operation(summary = "执行值java文件", description = "执行值java文件")
public Result<DataStructure> executionRuleVersion(@PathVariable("engineKey") String engineKey, @RequestBody DataStructure dataStructure) {
return Result.success(ruleVersionService.executionRuleValueVersion(engineKey, dataStructure));
}
/**
* java
*/
@RequiresPermissions("engine:ruleVersion:execution")
@PostMapping("/lineFile/{engineKey}")
@Operation(summary = "执行行java文件", description = "执行行java文件")
public Result<DataStructure[][]> executionLineRuleVersion(@PathVariable("engineKey") String engineKey, @RequestBody DataStructure[][] dataStructureRow) {
return Result.success(ruleVersionService.executionRowRuleVersion(engineKey, dataStructureRow));
}
/**
* java
*/
@RequiresPermissions("engine:ruleVersion:execution")
@PostMapping("/groupFile/{engineKey}")
@Operation(summary = "执行组java文件", description = "执行组java文件")
public Result<DataStructure[][]> executionGroupRuleVersion(@PathVariable("engineKey") String engineKey, @RequestBody DataStructure[][] dataStructureRows) {
return Result.success(ruleVersionService.executionRowsRuleVersion(engineKey, dataStructureRows));
}
/**
*
* @return
*/
@GetMapping("/dataSource/tableInfo")
@Operation(summary = "库表远调二级联动", description = "数据接入课表接入的二级联动,方便数据的选择")
public Result<List<TableInfoResp>> dataSourceList() {
return Result.success(ruleVersionService.dataSourceList());
}
/**
*
* @param id id
* @return
*/
@GetMapping("/dataSource/table/{id}")
public Result<List<DataAnalysis>> dataSource(@PathVariable("id") Long id) {
return Result.success(ruleVersionService.dataFindById(id));
}
/**
*
* @param dataTestReq
* @return ktlv
*/
@PostMapping("/getEtlTableData")
public Result<List<List<DataStructure>>> getEtlTableData(@RequestBody DataTestReq dataTestReq) {
return Result.success(ruleVersionService.testData(dataTestReq));
}
@GetMapping("/isClassExist/{className}")
public Result<Boolean> isClassExist(@PathVariable("className") String className) {
return Result.success(ruleVersionService.isClassExist(className));
}
/**
* (,,)
* @return List<RuleInfo>
*/
@GetMapping("/getEtlRuleAll")
public Result<List<RuleInfo>> getEtlRuleTypeByRuleId() {
return Result.success(ruleVersionService.getEtlRuleTypeByRuleId());
}
/**
* id
* @param id
* @return List<RuleVersion>
*/
@GetMapping("/getEtlRuleTypeVById")
public Result<List<RuleVersion>> getEtlRuleTypeVById(@RequestParam("id") Long id) {
return Result.success(ruleVersionService.getEtlRuleTypeVById(id));
}
/**
* id
* @param id
* @return RuleVersion
*/
@GetMapping("/getETlRuleTypeVersionById")
public Result<RuleVersion> getETlRuleTypeVersionById(@RequestParam("id") Long id) {
return Result.success( ruleVersionService.getById(id));
}
}

View File

@ -0,0 +1,19 @@
package com.muyu.etl.rule.mapper;
import java.util.List;
import com.muyu.etl.rule.domain.RuleInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.muyu.etl.rule.domain.req.EtlRuleListReq;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @author WangXin
* @date 2024-08-25
*/
@Mapper
public interface RuleInfoMapper extends BaseMapper<RuleInfo>{
List<RuleInfo> selectRuleInfoList(EtlRuleListReq ruleInfoReq);
}

View File

@ -0,0 +1,17 @@
package com.muyu.etl.rule.mapper;
import java.util.List;
import com.muyu.etl.rule.domain.RuleVersion;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @author wangXin
* @date 2024-08-25
*/
@Mapper
public interface RuleVersionMapper extends BaseMapper<RuleVersion>{
}

View File

@ -0,0 +1,89 @@
package com.muyu.etl.rule.operation;
import com.alibaba.fastjson2.JSONObject;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.enums.DataType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import java.util.Arrays;
import java.util.Iterator;
/**
* @Author WangXin
* @Data 2024/9/3
* @Description
* @Version 1.0.0
*/
@Data
@Builder
@AllArgsConstructor
@Log4j2
public class ArrayUtil<T> implements Iterator<T> {
private final T[] originalArray; // 原始数组
private T[] currentArray; // 当前数组,用于迭代
private int currentIndex; // 当前索引
private int lastReturnedIndex; // 上一次调用next()方法时返回的索引
private boolean canRemove = false; // 标记是否可以移除元素
public ArrayUtil(T[] array) {
this.originalArray = array;
this.currentArray = Arrays.copyOf(array, array.length);
this.currentIndex = 0;
}
@Override
public boolean hasNext() {
return currentIndex < currentArray.length;
}
@Override
public T next() {
if (!hasNext()) {
throw new IllegalStateException("No more elements");
}
lastReturnedIndex = currentIndex;
canRemove = true; // 调用next()后可以调用remove()
return currentArray[currentIndex++];
}
@Override
public void remove() {
if (!canRemove) {
throw new IllegalStateException("Cannot call remove() without calling next()");
}
// 删除元素并更新数组
System.arraycopy(currentArray, lastReturnedIndex + 1, currentArray, lastReturnedIndex, currentArray.length - lastReturnedIndex - 1);
currentArray = Arrays.copyOf(currentArray, currentArray.length - 1); // 缩小数组大小
currentIndex--; // 因为我们移除了当前元素,所以索引应该减一
canRemove = false;
}
public static void main(String[] args) {
DataStructure[] dataStructures = new DataStructure[6];
dataStructures[0] = DataStructure.builder().value("aaa1").key("name").type(DataType.STRING).label("姓名").build();
dataStructures[1] = DataStructure.builder().value("aaa2").key("name").type(DataType.STRING).label("姓名").build();
dataStructures[2] = DataStructure.builder().value("aaa3").key("name").type(DataType.STRING).label("姓名").build();
dataStructures[3] = DataStructure.builder().value("aaa4").key("name").type(DataType.STRING).label("姓名").build();
dataStructures[4] = DataStructure.builder().value("aaa5").key("name").type(DataType.STRING).label("姓名").build();
dataStructures[5] = DataStructure.builder().value("aaa6").key("name").type(DataType.STRING).label("姓名").build();
ArrayUtil<DataStructure> dataStructureArrayUtil = new ArrayUtil<>(dataStructures);
log.info(dataStructureArrayUtil.originalArray.length);
log.info(JSONObject.toJSONString(dataStructureArrayUtil.originalArray));
while (dataStructureArrayUtil.hasNext()){
DataStructure next = dataStructureArrayUtil.next();
if (next.getValue().equals("aaa3")){
dataStructureArrayUtil.remove();
}
}
log.info(dataStructureArrayUtil.currentArray.length);
log.info(Arrays.toString(dataStructureArrayUtil.currentArray));
}
}

View File

@ -0,0 +1,37 @@
package com.muyu.etl.rule.service;
import java.util.List;
import com.muyu.etl.rule.domain.RuleInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.etl.rule.domain.req.EtlRuleListReq;
/**
* Service
*
* @author WangXin
* @date 2024-08-25
*/
public interface IRuleInfoService extends IService<RuleInfo> {
/**
*
*
* @param id
* @return
*/
public RuleInfo selectRuleInfoById(Long id);
/**
*
* @param ruleInfoReq
* @return
*/
public List<RuleInfo> selectRuleInfoList(EtlRuleListReq ruleInfoReq);
/**
* id
* @param ruleInfo
* @return
*/
Boolean checkIdUnique(RuleInfo ruleInfo);
}

View File

@ -0,0 +1,131 @@
package com.muyu.etl.rule.service;
import java.util.List;
import com.muyu.common.core.domain.Result;
import com.muyu.etl.data.access.domain.DataAnalysis;
import com.muyu.etl.data.access.domain.resp.TableInfoResp;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.domain.RuleVersion;
import com.baomidou.mybatisplus.extension.service.IService;
import com.muyu.etl.rule.domain.req.DataTestReq;
import com.muyu.etl.rule.domain.req.ExecutionRuleVersionReq;
import com.muyu.etl.rule.domain.req.WriteFileReq;
import org.apache.commons.codec.language.bm.RuleType;
/**
* Service
*
* @author wangXin
* @date 2024-08-25
*/
public interface IRuleVersionService extends IService<RuleVersion> {
/**
*
*
* @param id
* @return
*/
public RuleVersion selectRuleVersionById(Long id);
/**
*
*
* @param ruleVersion
* @return
*/
public List<RuleVersion> selectRuleVersionList(RuleVersion ruleVersion);
/**
* id
* @param ruleVersion
* @return
*/
Boolean checkIdUnique(RuleVersion ruleVersion);
/**
* id
* @param id id
* @return
*/
List<RuleVersion> selectRuleVersionListByRuleId(Long id);
/**
*
* @param fileName
* @return
*/
String readFile(String fileName);
/**
*
* @param writeFileReq
*/
void writeFile(WriteFileReq writeFileReq);
/**
*
* @param executionRuleVersionReq
*/
Object executionRuleVersion(ExecutionRuleVersionReq executionRuleVersionReq);
/**
*
* @param engineKey
* @param dataStructure
*/
DataStructure executionRuleValueVersion(String engineKey, DataStructure dataStructure);
/**
*
* @param engineKey
* @param dataStructureRow
*/
DataStructure[][] executionRowRuleVersion(String engineKey, DataStructure[][] dataStructureRow);
/**
*
* @param engineKey
* @param dataStructureRows
*/
DataStructure[][] executionRowsRuleVersion(String engineKey, DataStructure[][] dataStructureRows);
/**
*
* @return
*/
List<TableInfoResp> dataSourceList();
/**
* id
* @param id id
* @return
*/
List<DataAnalysis> dataFindById(Long id);
/**
*
* @param dataTestReq
* @return
*/
List<List<DataStructure>> testData(DataTestReq dataTestReq);
/**
*
* @param className
* @return
*/
Boolean isClassExist(String className);
/**
* (,,)
* @return List<RuleInfo>
*/
List<RuleInfo> getEtlRuleTypeByRuleId();
List<RuleVersion> getEtlRuleTypeVById(Long id);
}

View File

@ -0,0 +1,69 @@
package com.muyu.etl.rule.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.domain.req.EtlRuleListReq;
import com.muyu.etl.rule.mapper.RuleInfoMapper;
import com.muyu.etl.rule.service.IRuleInfoService;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.List;
/**
* Service
*
* @author WangXin
* @date 2024-08-25
*/
@Service
public class RuleInfoServiceImpl
extends ServiceImpl<RuleInfoMapper, RuleInfo>
implements IRuleInfoService {
@Resource
private RuleInfoMapper ruleInfoMapper;
/**
*
*
* @param id
* @return
*/
@Override
public RuleInfo selectRuleInfoById(Long id)
{
LambdaQueryWrapper<RuleInfo> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(RuleInfo::getId, id);
return this.getOne(queryWrapper);
}
/**
*
*
* @param ruleInfoReq
* @return
*/
@Override
public List<RuleInfo> selectRuleInfoList(EtlRuleListReq ruleInfoReq)
{
return ruleInfoMapper.selectRuleInfoList(ruleInfoReq);
}
/**
*
* @param ruleInfo
* @return
*/
@Override
public Boolean checkIdUnique(RuleInfo ruleInfo) {
LambdaQueryWrapper<RuleInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RuleInfo::getId, ruleInfo.getId());
return this.count(queryWrapper) > 0;
}
}

View File

@ -0,0 +1,383 @@
package com.muyu.etl.rule.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.muyu.common.core.utils.OssUtil;
import com.muyu.common.core.utils.StringUtils;
import com.muyu.common.core.utils.sign.Base64;
import com.muyu.etl.data.access.domain.DataAnalysis;
import com.muyu.etl.data.access.domain.req.EtlDataSqlReq;
import com.muyu.etl.data.access.domain.resp.TableInfoResp;
import com.muyu.etl.data.access.remote.RemoteDataAnalysisService;
import com.muyu.etl.data.access.remote.RemoteEtlDataService;
import com.muyu.etl.data.access.remote.RemoteTableInfoService;
import com.muyu.etl.domain.DataStructure;
import com.muyu.etl.rule.domain.RuleInfo;
import com.muyu.etl.rule.engine.bean.constant.FileConstants;
import com.muyu.etl.rule.engine.core.EngineContainer;
import com.muyu.etl.rule.engine.core.EngineExecution;
import com.muyu.etl.rule.engine.core.classLoad.JavaBinaryClassLoader;
import com.muyu.etl.rule.engine.core.complier.SourceCodeCompiler;
import com.muyu.etl.rule.engine.util.FileLoadUtil;
import com.muyu.etl.rule.basic.BasicEngine;
import com.muyu.etl.rule.config.EngineConfig;
import com.muyu.etl.rule.domain.RuleVersion;
import com.muyu.etl.rule.domain.req.DataSqlField;
import com.muyu.etl.rule.domain.req.DataTestReq;
import com.muyu.etl.rule.domain.req.ExecutionRuleVersionReq;
import com.muyu.etl.rule.domain.req.WriteFileReq;
import com.muyu.etl.rule.mapper.RuleVersionMapper;
import com.muyu.etl.rule.service.IRuleVersionService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.language.bm.RuleType;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* Service
*
* @author wangXin
* @date 2024-08-25
*/
@Service
@Log4j2
public class RuleVersionServiceImpl
extends ServiceImpl<RuleVersionMapper, RuleVersion>
implements IRuleVersionService {
@Resource
private EngineConfig engineConfig;
@Resource
private RemoteEtlDataService remoteEtlDataService;
@Resource
private RemoteTableInfoService remoteTableInfoService;
@Resource
private RemoteDataAnalysisService remoteDataAnalysisService;
/**
*
*
* @param id
* @return
*/
@Override
public RuleVersion selectRuleVersionById(Long id) {
LambdaQueryWrapper<RuleVersion> queryWrapper = new LambdaQueryWrapper<>();
Assert.notNull(id, "id不可为空");
queryWrapper.eq(RuleVersion::getId, id);
return this.getOne(queryWrapper);
}
/**
*
*
* @param ruleVersion
* @return
*/
@Override
public List<RuleVersion> selectRuleVersionList(RuleVersion ruleVersion) {
LambdaQueryWrapper<RuleVersion> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotEmpty(ruleVersion.getRuleVersionName())) {
queryWrapper.like(RuleVersion::getRuleVersionName, ruleVersion.getRuleVersionName());
}
if (StringUtils.isNotEmpty(ruleVersion.getRuleVersionCode())) {
queryWrapper.eq(RuleVersion::getRuleVersionCode, ruleVersion.getRuleVersionCode());
}
if (ruleVersion.getRuleVersionIsActivation() != null) {
queryWrapper.eq(RuleVersion::getRuleVersionIsActivation, ruleVersion.getRuleVersionIsActivation());
}
if (ruleVersion.getRuleVersionIsTest() != null) {
queryWrapper.eq(RuleVersion::getRuleVersionIsTest, ruleVersion.getRuleVersionIsTest());
}
if (ruleVersion.getRuleVersionStatus() != null) {
queryWrapper.eq(RuleVersion::getRuleVersionStatus, ruleVersion.getRuleVersionStatus());
}
return this.list(queryWrapper);
}
/**
*
*
* @param ruleVersion
* @return
*/
@Override
public Boolean checkIdUnique(RuleVersion ruleVersion) {
LambdaQueryWrapper<RuleVersion> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RuleVersion::getId, ruleVersion.getId());
return this.count(queryWrapper) > 0;
}
/**
* id
*
* @param id Id
* @return
*/
@Override
public List<RuleVersion> selectRuleVersionListByRuleId(Long id) {
LambdaQueryWrapper<RuleVersion> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RuleVersion::getRuleId, id);
return this.list(queryWrapper).stream()
.peek(ruleVersion -> ruleVersion.setClassContent(readFile(ruleVersion.getRuleVersionClass())))
.collect(Collectors.toList());
}
/**
*
*
* @param fileName
* @return
*/
@Override
public String readFile(String fileName) {
log.info("readFile请求入参[fileName:{}]", fileName);
return FileLoadUtil.readFile(engineConfig.getSourceLocation(), fileName);
}
/**
*
*
* @param writeFileReq
*/
@Override
public void writeFile(WriteFileReq writeFileReq) {
String content = new String(Base64.decode(writeFileReq.getContent()));
FileLoadUtil.writeFile(engineConfig.getSourceLocation(), writeFileReq.getFileName(), content);
OssUtil.uploadFile(engineConfig.getSourceLocation() + FileConstants.FILE_DELIMITER + writeFileReq.getFileName().split("_")[0] + FileConstants.FILE_DELIMITER + writeFileReq.getFileName() + FileConstants.JAVA_SUFFIX);
}
/**
*
*
* @param executionRuleVersionReq
*/
@Override
public Object executionRuleVersion(ExecutionRuleVersionReq executionRuleVersionReq) {
return executionRule(executionRuleVersionReq);
}
/**
*
*
* @param engineKey
* @param dataStructure
*/
@Override
public DataStructure executionRuleValueVersion(String engineKey, DataStructure dataStructure) {
return executionValueRule(engineKey, dataStructure);
}
/**
*
*
* @param engineKey
* @param dataStructureRow
*/
@Override
public DataStructure[][] executionRowRuleVersion(String engineKey, DataStructure[][] dataStructureRow) {
ArrayList<DataStructure[]> dataStructures = new ArrayList<>();
for (DataStructure[] dataStructure : dataStructureRow) {
DataStructure[] dataStructure1 = executionValueRule(engineKey, dataStructure);
if (dataStructure1 != null && dataStructure1.length > 0) {
dataStructures.add(dataStructure1);
}
}
return dataStructures.toArray(new DataStructure[dataStructures.size()][]);
}
/**
*
*
* @param engineKey
* @param dataStructureRows
*/
@Override
public DataStructure[][] executionRowsRuleVersion(String engineKey, DataStructure[][] dataStructureRows) {
return executionValueRule(engineKey, dataStructureRows);
}
/**
*
*
* @return
*/
@Override
public List<TableInfoResp> dataSourceList() {
return remoteTableInfoService.findByTableName().getData();
}
@Override
public List<DataAnalysis> dataFindById(Long id) {
return remoteDataAnalysisService.findDataAnalysisByTableId(id).getData();
}
@Override
public List<List<DataStructure>> testData(DataTestReq dataTestReq) {
return remoteEtlDataService.selEtlData(EtlDataSqlReq.builder()
.sql(spliceSql(dataTestReq))
.basicId(dataTestReq.getBasicId())
.build()).getData();
}
@Override
public Boolean isClassExist(String className) {
LambdaQueryWrapper<RuleVersion> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RuleVersion::getRuleVersionClass, className);
return this.exists(queryWrapper);
}
/**
* sql
*
* @param dataTestReq
* @return
*/
private String spliceSql(DataTestReq dataTestReq) {
List<String> list = dataTestReq.getRows().stream().map(DataSqlField::getColumnName).collect(Collectors.toList());
String sql = "SELECT " + list.stream().collect(Collectors.joining(",")) + " FROM " + dataTestReq.getTableName();
log.info("拼接SQL语句为 --->[{}]", sql);
return sql;
}
/**
*
*
* @param executionRuleVersionReq
* @return
*/
private Object executionRule(ExecutionRuleVersionReq executionRuleVersionReq) {
//将java文件编译成class文件
SourceCodeCompiler.javaCompilerPath(engineConfig.getSourceLocation());
//获取所有class文件的class对象
Map<String, Class<?>> stringClassMap = JavaBinaryClassLoader
.loadClassByLocation(engineConfig.getPackageName(),
engineConfig.sourceLocation);
//实将所有class对象进行例化并进行存储
stringClassMap.forEach((k, v) -> {
EngineContainer.loadEngineInstance(engineConfig.methodName, k, v);
});
return EngineExecution.argumentEngineExe(executionRuleVersionReq.getEngineKey(), executionRuleVersionReq.getParams());
}
/**
* class
*/
private String javaCompile(String fileName) {
//将java文件编译成class文件
SourceCodeCompiler.javaCompiler("", new File(getFilePath(fileName, FileConstants.JAVA_SUFFIX)));
//返回oss中class文件地址
return OssUtil.uploadFile(getFilePath(fileName, FileConstants.CLASS_SUFFIX));
}
/**
*
*
* @param fileName
* @param endWih
* @return
*/
private String getFilePath(String fileName, String endWih) {
return engineConfig.getSourceLocation() + FileConstants.FILE_DELIMITER + fileName.split("_")[0] + FileConstants.FILE_DELIMITER + fileName + endWih;
}
/**
*
*
* @param engineKey
*/
private <T> T executionValueRule(String engineKey, T t) {
log.info("配置参数为 ------》 SourceLocation{} | PackageName{}", engineConfig.getSourceLocation(), engineConfig.getPackageName());
log.info("请求类-----》 {}", engineKey);
log.info("请求参数为----》{}", JSONObject.toJSONString(t));
String path = engineConfig.getSourceLocation() + FileConstants.FILE_DELIMITER + engineKey.split("_")[0];
//将java文件编译成class文件
SourceCodeCompiler.javaCompiler(engineConfig.classConfigPath, path + "/classes", path, engineKey);
//获取所有class文件的class对象
Map<String, Class<?>> stringClassMap = JavaBinaryClassLoader
.loadClassByLocation(engineConfig.getPackageName(),
path+ "/classes");
log.info("[{}] 类编译成功 ", engineKey);
//实将所有class对象进行例化并进行存储
stringClassMap.forEach((k, v) -> {
EngineContainer.loadEngineInstance(engineConfig.methodName, k, v);
});
log.info("[{}] 类实例化成功", engineKey);
ConcurrentHashMap<String, Object> instanceMap = EngineContainer.instanceMap;
Object object = instanceMap.get(engineKey);
log.info("返回值对象object:{}", object);
if (object != null && object instanceof BasicEngine<?>) {
BasicEngine<T> engine = (BasicEngine<T>) object;
engine.set(t);
engine.execution();
log.info("[{}]类加载成功", engineKey);
T engineData = engine.get();
log.info("[{}]处理数据结果为[{}]", engineKey, JSONObject.toJSONString(engineData));
return engineData;
} else {
throw new RuntimeException("对象类型错误");
}
}
public static void main(String[] args) {
// String engineKey = "TelTuoMing";
// String locationPath = "C:\\Users\\wx\\Desktop\\测试";
// String page = "com.muyu.etl.rule";
//
// SourceCodeCompiler.javaCompilerPath(locationPath);
//
// Map<String, Class<?>> stringClassMap = JavaBinaryClassLoader
// .loadClassByLocation(page, locationPath);
//
// stringClassMap.forEach((k, v) -> {
// EngineContainer.loadEngineInstance("run", k, v);
// });
//
// DataStructure dataStructure = new DataStructure();
// dataStructure.setValue("15335893491");
// dataStructure.setType(DataType.STRING);
// dataStructure.setKey("tel");
// dataStructure.setLabel("手机号");
//
// ConcurrentHashMap<String, Object> instanceMap = EngineContainer.instanceMap;
// Object object = instanceMap.get(engineKey);
// if (object != null && object instanceof BasicEngine<?>) {
// BasicEngine<DataStructure> engine = (BasicEngine<DataStructure>) object;
// engine.set(dataStructure);
// engine.execution();
// }
}
/**
* (,,)
* @return List<RuleInfo>
*/
@Override
public List<RuleInfo> getEtlRuleTypeByRuleId() {
return List.of();
}
@Override
public List<RuleVersion> getEtlRuleTypeVById(Long id) {
return List.of();
}
}

View File

@ -0,0 +1,2 @@
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}

View File

@ -0,0 +1,56 @@
# Tomcat
server:
port: 10003
# nacos线上地址
nacos:
addr: 10.0.1.97:8848
user-name: nacos
password: nacos
namespace: wu_zu_cloud
# Spring
spring:
main:
allow-bean-definition-overriding: true
application:
# 应用名称
name: cloud-rule-engine
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
config:
# 服务注册地址
server-addr: ${nacos.addr}
# nacos用户名
username: ${nacos.user-name}
# nacos密码
password: ${nacos.password}
# 命名空间
namespace: ${nacos.namespace}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
# 系统共享配置
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# 系统环境Config共享配置
- application-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# xxl-job 配置文件
- application-xxl-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
# engine配置
- engine-config-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
logging:
level:
com.muyu.system.mapper: DEBUG

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/etl-rules-engine"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/etl-rules-engine"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.sky.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/etl-rules-engine"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<property name="log.sky.pattern" value="%d{HH:mm:ss.SSS} %yellow([%tid]) [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.sky.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 使用gRpc将日志发送到skywalking服务端 -->
<appender name="GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>${log.sky.pattern}</Pattern>
</layout>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="GRPC_LOG"/>
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.muyu.etl.rule.mapper.RuleInfoMapper">
<resultMap type="com.muyu.etl.rule.domain.RuleInfo" id="RuleInfoResult">
<result property="id" column="id" />
<result property="ruleName" column="rule_name" />
<result property="ruleCode" column="rule_code" />
<result property="ruleTypeValue" column="rule_type_value" />
<result property="ruleLevelId" column="rule_level_id" />
<result property="isActivation" column="is_activation" />
<result property="status" column="status" />
<result property="ruleExplain" column="rule_explain" />
<result property="createBy" column="CREATE_BY" />
<result property="createTime" column="CREATE_TIME" />
<result property="updateBy" column="UPDATE_BY" />
<result property="updateTime" column="UPDATE_TIME" />
<result property="remark" column="remark" />
<result property="createByName" column="CREATE_BY_NAME" />
<result property="updateByName" column="UPDATE_BY_NAME" />
</resultMap>
<sql id="selectRuleInfoVo">
select id, rule_name, rule_code, rule_type_value, rule_level_id, is_activation, status, rule_explain, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, remark, CREATE_BY_NAME, UPDATE_BY_NAME from etl_rule_info
</sql>
<select id="selectRuleInfoList" parameterType="com.muyu.etl.rule.domain.RuleInfo" resultMap="RuleInfoResult">
<include refid="selectRuleInfoVo"/>
<where>
<if test="ruleName != null and ruleName != ''"> and rule_name like concat('%', #{ruleName}, '%')</if>
<if test="ruleTypeValue != null and ruleTypeValue != ''"> and rule_type_value = #{ruleTypeValue}</if>
<if test="isActivation != null and isActivation != ''"> and is_activation = #{isActivation}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
</where>
</select>
<select id="selectRuleInfoById" parameterType="Long" resultMap="RuleInfoResult">
<include refid="selectRuleInfoVo"/>
where id = #{id}
</select>
<insert id="insertRuleInfo" parameterType="com.muyu.etl.rule.domain.RuleInfo" useGeneratedKeys="true" keyProperty="id">
insert into etl_rule_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="ruleName != null">rule_name,</if>
<if test="ruleCode != null">rule_code,</if>
<if test="ruleTypeValue != null">rule_type_value,</if>
<if test="ruleLevelId != null">rule_level_id,</if>
<if test="isActivation != null">is_activation,</if>
<if test="status != null">status,</if>
<if test="ruleExplain != null">rule_explain,</if>
<if test="createBy != null">CREATE_BY,</if>
<if test="createTime != null">CREATE_TIME,</if>
<if test="updateBy != null">UPDATE_BY,</if>
<if test="updateTime != null">UPDATE_TIME,</if>
<if test="remark != null">remark,</if>
<if test="createByName != null">CREATE_BY_NAME,</if>
<if test="updateByName != null">UPDATE_BY_NAME,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="ruleName != null">#{ruleName},</if>
<if test="ruleCode != null">#{ruleCode},</if>
<if test="ruleTypeValue != null">#{ruleTypeValue},</if>
<if test="ruleLevelId != null">#{ruleLevelId},</if>
<if test="isActivation != null">#{isActivation},</if>
<if test="status != null">#{status},</if>
<if test="ruleExplain != null">#{ruleExplain},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
<if test="createByName != null">#{createByName},</if>
<if test="updateByName != null">#{updateByName},</if>
</trim>
</insert>
<update id="updateRuleInfo" parameterType="com.muyu.etl.rule.domain.RuleInfo">
update etl_rule_info
<trim prefix="SET" suffixOverrides=",">
<if test="ruleName != null">rule_name = #{ruleName},</if>
<if test="ruleCode != null">rule_code = #{ruleCode},</if>
<if test="ruleTypeValue != null">rule_type_value = #{ruleTypeValue},</if>
<if test="ruleLevelId != null">rule_level_id = #{ruleLevelId},</if>
<if test="isActivation != null">is_activation = #{isActivation},</if>
<if test="status != null">status = #{status},</if>
<if test="ruleExplain != null">rule_explain = #{ruleExplain},</if>
<if test="createBy != null">CREATE_BY = #{createBy},</if>
<if test="createTime != null">CREATE_TIME = #{createTime},</if>
<if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
<if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="createByName != null">CREATE_BY_NAME = #{createByName},</if>
<if test="updateByName != null">UPDATE_BY_NAME = #{updateByName},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteRuleInfoById" parameterType="Long">
delete from etl_rule_info where id = #{id}
</delete>
<delete id="deleteRuleInfoByIds" parameterType="String">
delete from etl_rule_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.muyu.etl.rule.mapper.RuleVersionMapper">
<resultMap type="com.muyu.etl.rule.domain.RuleVersion" id="RuleVersionResult">
<result property="id" column="id" />
<result property="ruleVersionClass" column="rule_version_class" />
<result property="ruleVersionName" column="rule_version_name" />
<result property="ruleVersionCode" column="rule_version_code" />
<result property="ruleVersionIsActivation" column="rule_version_is_activation" />
<result property="ruleVersionIsTest" column="rule_version_is_test" />
<result property="ruleVersionStatus" column="rule_version_status" />
<result property="ruleVersionDescribed" column="rule_version_described" />
<result property="ruleId" column="rule_id" />
<result property="createBy" column="CREATE_BY" />
<result property="createTime" column="CREATE_TIME" />
<result property="updateBy" column="UPDATE_BY" />
<result property="updateTime" column="UPDATE_TIME" />
<result property="remark" column="remark" />
<result property="createByName" column="CREATE_BY_NAME" />
<result property="updateByName" column="UPDATE_BY_NAME" />
</resultMap>
<sql id="selectRuleVersionVo">
select id, rule_version_class, rule_version_name, rule_version_code, rule_version_is_activation, rule_version_is_test, rule_version_status, rule_version_described, rule_id, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, remark, CREATE_BY_NAME, UPDATE_BY_NAME from etl_rule_version
</sql>
<select id="selectRuleVersionList" parameterType="com.muyu.etl.rule.domain.RuleVersion" resultMap="RuleVersionResult">
<include refid="selectRuleVersionVo"/>
<where>
<if test="ruleVersionName != null and ruleVersionName != ''"> and rule_version_name like concat('%', #{ruleVersionName}, '%')</if>
<if test="ruleVersionCode != null and ruleVersionCode != ''"> and rule_version_code = #{ruleVersionCode}</if>
<if test="ruleVersionIsActivation != null and ruleVersionIsActivation != ''"> and rule_version_is_activation = #{ruleVersionIsActivation}</if>
<if test="ruleVersionIsTest != null "> and rule_version_is_test = #{ruleVersionIsTest}</if>
<if test="ruleVersionStatus != null "> and rule_version_status = #{ruleVersionStatus}</if>
</where>
</select>
<select id="selectRuleVersionById" parameterType="Long" resultMap="RuleVersionResult">
<include refid="selectRuleVersionVo"/>
where id = #{id}
</select>
<insert id="insertRuleVersion" parameterType="com.muyu.etl.rule.domain.RuleVersion" useGeneratedKeys="true" keyProperty="id">
insert into etl_rule_version
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="ruleVersionClass != null">rule_version_class,</if>
<if test="ruleVersionName != null">rule_version_name,</if>
<if test="ruleVersionCode != null">rule_version_code,</if>
<if test="ruleVersionIsActivation != null">rule_version_is_activation,</if>
<if test="ruleVersionIsTest != null">rule_version_is_test,</if>
<if test="ruleVersionStatus != null">rule_version_status,</if>
<if test="ruleVersionDescribed != null">rule_version_described,</if>
<if test="ruleId != null">rule_id,</if>
<if test="createBy != null">CREATE_BY,</if>
<if test="createTime != null">CREATE_TIME,</if>
<if test="updateBy != null">UPDATE_BY,</if>
<if test="updateTime != null">UPDATE_TIME,</if>
<if test="remark != null">remark,</if>
<if test="createByName != null">CREATE_BY_NAME,</if>
<if test="updateByName != null">UPDATE_BY_NAME,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="ruleVersionClass != null">#{ruleVersionClass},</if>
<if test="ruleVersionName != null">#{ruleVersionName},</if>
<if test="ruleVersionCode != null">#{ruleVersionCode},</if>
<if test="ruleVersionIsActivation != null">#{ruleVersionIsActivation},</if>
<if test="ruleVersionIsTest != null">#{ruleVersionIsTest},</if>
<if test="ruleVersionStatus != null">#{ruleVersionStatus},</if>
<if test="ruleVersionDescribed != null">#{ruleVersionDescribed},</if>
<if test="ruleId != null">#{ruleId},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
<if test="createByName != null">#{createByName},</if>
<if test="updateByName != null">#{updateByName},</if>
</trim>
</insert>
<update id="updateRuleVersion" parameterType="com.muyu.etl.rule.domain.RuleVersion">
update etl_rule_version
<trim prefix="SET" suffixOverrides=",">
<if test="ruleVersionClass != null">rule_version_class = #{ruleVersionClass},</if>
<if test="ruleVersionName != null">rule_version_name = #{ruleVersionName},</if>
<if test="ruleVersionCode != null">rule_version_code = #{ruleVersionCode},</if>
<if test="ruleVersionIsActivation != null">rule_version_is_activation = #{ruleVersionIsActivation},</if>
<if test="ruleVersionIsTest != null">rule_version_is_test = #{ruleVersionIsTest},</if>
<if test="ruleVersionStatus != null">rule_version_status = #{ruleVersionStatus},</if>
<if test="ruleVersionDescribed != null">rule_version_described = #{ruleVersionDescribed},</if>
<if test="ruleId != null">rule_id = #{ruleId},</if>
<if test="createBy != null">CREATE_BY = #{createBy},</if>
<if test="createTime != null">CREATE_TIME = #{createTime},</if>
<if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
<if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="createByName != null">CREATE_BY_NAME = #{createByName},</if>
<if test="updateByName != null">UPDATE_BY_NAME = #{updateByName},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteRuleVersionById" parameterType="Long">
delete from etl_rule_version where id = #{id}
</delete>
<delete id="deleteRuleVersionByIds" parameterType="String">
delete from etl_rule_version where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

35
pom.xml 100644
View File

@ -0,0 +1,35 @@
<?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>cloud-modules</artifactId>
<version>3.6.5</version>
</parent>
<artifactId>cloud-rule-engine</artifactId>
<version>3.6.5</version>
<packaging>pom</packaging>
<modules>
<module>etl-rule-common</module>
<module>etl-rule-remote</module>
<module>etl-rule-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>
<distributionManagement>
<repository>
<id>yun-releases</id>
<name>yun-releases</name>
<url>http://10.0.1.3:8081/repository/maven-releases/</url>
</repository>
</distributionManagement>
</project>