Browse Source

!127 enhancement #I5XWL2 数据库插件支持脚本的存储
Merge pull request !127 from 与或非/issues/I5XWL2

铂赛东 2 years ago
parent
commit
901bd35160

+ 169 - 154
liteflow-core/src/main/java/com/yomahub/liteflow/enums/NodeTypeEnum.java

@@ -16,170 +16,185 @@ import java.util.function.Predicate;
 
 /**
  * 节点类型枚举
+ *
  * @author Bryan.Zhang
  * @since 2.6.0
  */
 public enum NodeTypeEnum {
 
-    COMMON("common","普通", false, NodeComponent.class),
+	COMMON("common", "普通", false, NodeComponent.class),
 
-    SWITCH("switch", "选择", false, NodeSwitchComponent.class),
+	SWITCH("switch", "选择", false, NodeSwitchComponent.class),
 
-    IF("if", "条件", false, NodeIfComponent.class),
+	IF("if", "条件", false, NodeIfComponent.class),
 
-    FOR("for","循环次数", false, NodeForComponent.class),
+	FOR("for", "循环次数", false, NodeForComponent.class),
 
-    WHILE("while", "循环条件", false, NodeWhileComponent.class),
+	WHILE("while", "循环条件", false, NodeWhileComponent.class),
 
-    BREAK("break", "循环跳出", false, NodeBreakComponent.class),
-    SCRIPT("script","脚本", true, ScriptCommonComponent.class),
+	BREAK("break", "循环跳出", false, NodeBreakComponent.class),
+	SCRIPT("script", "脚本", true, ScriptCommonComponent.class),
 
-    SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class),
-
-    IF_SCRIPT("if_script", "条件脚本", true, ScriptIfComponent.class),
-
-    FOR_SCRIPT("for_script", "循环次数脚本", true, ScriptForComponent.class),
-
-    WHILE_SCRIPT("while_script", "循环条件脚本", true, ScriptWhileComponent.class),
-
-    BREAK_SCRIPT("break_script", "循环跳出脚本", true, ScriptBreakComponent.class)
-    ;
-
-    private static final Logger LOG = LoggerFactory.getLogger(NodeTypeEnum.class);
+	SWITCH_SCRIPT("switch_script", "选择脚本", true, ScriptSwitchComponent.class),
 
-    private String code;
-    private String name;
-
-    private boolean isScript;
-
-    private Class<? extends NodeComponent> mappingClazz;
-
-    NodeTypeEnum(String code, String name, boolean isScript, Class<? extends NodeComponent> mappingClazz) {
-        this.code = code;
-        this.name = name;
-        this.isScript = isScript;
-        this.mappingClazz = mappingClazz;
-    }
-
-    public String getCode() {
-        return code;
-    }
-
-    public void setCode(String code) {
-        this.code = code;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public boolean isScript() {
-        return isScript;
-    }
-
-    public void setScript(boolean script) {
-        isScript = script;
-    }
-
-    public Class<? extends NodeComponent> getMappingClazz() {
-        return mappingClazz;
-    }
-
-    public void setMappingClazz(Class<? extends NodeComponent> mappingClazz) {
-        this.mappingClazz = mappingClazz;
-    }
-
-    public static NodeTypeEnum getEnumByCode(String code) {
-        for (NodeTypeEnum e : NodeTypeEnum.values()) {
-            if (e.getCode().equals(code)) {
-                return e;
-            }
-        }
-        return null;
-    }
-
-    public static NodeTypeEnum guessTypeBySuperClazz(Class<?> clazz){
-        Class<?> superClazz = clazz;
-        while(true){
-            superClazz = superClazz.getSuperclass();
-            if (superClazz.getPackage().getName().startsWith("com.yomahub.liteflow.core")){
-                break;
-            }
-            if(superClazz.equals(Object.class)){
-                return null;
-            }
-        }
-
-        for (NodeTypeEnum e : NodeTypeEnum.values()) {
-            if (e.getMappingClazz().equals(superClazz)) {
-                return e;
-            }
-        }
-        return null;
-    }
-
-    public static NodeTypeEnum guessType(Class<?> clazz){
-        NodeTypeEnum nodeType = guessTypeBySuperClazz(clazz);
-        if (nodeType == null){
-            //尝试从类声明处进行推断
-            LiteflowCmpDefine liteflowCmpDefine = clazz.getAnnotation(LiteflowCmpDefine.class);
-            if (liteflowCmpDefine != null){
-                //类声明方式中@LiteflowMethod是无需设置nodeId的
-                //但是如果设置了,那么核心逻辑其实是取类上定义的id的
-                //这种可以运行,但是理解起来不大好理解,所以给出提示,建议不要这么做
-                boolean mixDefined = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
-                    LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
-                    if (liteflowMethod != null){
-                        return StrUtil.isNotBlank(liteflowMethod.nodeId());
-                    }else{
-                        return false;
-                    }
-                });
-
-                if (mixDefined){
-                    LOG.warn("[[[WARNING!!!]]]The @liteflowMethod in the class[{}] defined by @liteflowCmpDefine should not configure the nodeId again!",
-                            clazz.getName());
-                }
-
-
-                //在返回之前,还要对方法级别的@LiteflowMethod进行检查,如果存在方法上的类型与类上的不一致时,给予警告信息
-                AtomicReference<Method> differenceTypeMethod = new AtomicReference<>();
-                boolean hasDifferenceNodeType = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
-                    LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
-                    if (liteflowMethod != null){
-                        if (!liteflowMethod.nodeType().equals(liteflowCmpDefine.value())){
-                            differenceTypeMethod.set(method);
-                            return true;
-                        }else{
-                            return false;
-                        }
-                    }else{
-                        return false;
-                    }
-                });
-
-                //表示存在不一样的类型
-                if (hasDifferenceNodeType){
-                    LOG.warn("[[[WARNING!!!]]]The nodeType in @liteflowCmpDefine declared on the class[{}] does not match the nodeType in @liteflowMethod declared on the method[{}]!",
-                            clazz.getName(), differenceTypeMethod.get().getName());
-                }
-
-                return liteflowCmpDefine.value();
-            }
-
-            //再尝试声明式组件这部分的推断
-            LiteflowMethod liteflowMethod = Arrays.stream(clazz.getDeclaredMethods()).map(
-                    method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class)
-            ).filter(Objects::nonNull).filter(lfMethod -> lfMethod.value().isMainMethod()).findFirst().orElse(null);
-
-            if (liteflowMethod != null) {
-                nodeType = liteflowMethod.nodeType();
-            }
-        }
-        return nodeType;
-    }
+	IF_SCRIPT("if_script", "条件脚本", true, ScriptIfComponent.class),
+
+	FOR_SCRIPT("for_script", "循环次数脚本", true, ScriptForComponent.class),
+
+	WHILE_SCRIPT("while_script", "循环条件脚本", true, ScriptWhileComponent.class),
+
+	BREAK_SCRIPT("break_script", "循环跳出脚本", true, ScriptBreakComponent.class);
+
+	private static final Logger LOG = LoggerFactory.getLogger(NodeTypeEnum.class);
+
+	private String code;
+	private String name;
+
+	private boolean isScript;
+
+	private Class<? extends NodeComponent> mappingClazz;
+
+	NodeTypeEnum(String code, String name, boolean isScript, Class<? extends NodeComponent> mappingClazz) {
+		this.code = code;
+		this.name = name;
+		this.isScript = isScript;
+		this.mappingClazz = mappingClazz;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public boolean isScript() {
+		return isScript;
+	}
+
+	public void setScript(boolean script) {
+		isScript = script;
+	}
+
+	public Class<? extends NodeComponent> getMappingClazz() {
+		return mappingClazz;
+	}
+
+	public void setMappingClazz(Class<? extends NodeComponent> mappingClazz) {
+		this.mappingClazz = mappingClazz;
+	}
+
+	public static NodeTypeEnum getEnumByCode(String code) {
+		for (NodeTypeEnum e : NodeTypeEnum.values()) {
+			if (e.getCode().equals(code)) {
+				return e;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * 根据节点类型判断是否是脚本节点
+	 *
+	 * @param code 节点类型
+	 * @return 是否是脚本节点
+	 */
+	public static boolean isScriptNodeType(String code) {
+		return SCRIPT.getCode().equals(code) ||
+				SWITCH_SCRIPT.getCode().equals(code) ||
+				IF_SCRIPT.getCode().equals(code) ||
+				FOR_SCRIPT.getCode().equals(code) ||
+				WHILE_SCRIPT.getCode().equals(code) ||
+				BREAK_SCRIPT.getCode().equals(code);
+	}
+
+	public static NodeTypeEnum guessTypeBySuperClazz(Class<?> clazz) {
+		Class<?> superClazz = clazz;
+		while (true) {
+			superClazz = superClazz.getSuperclass();
+			if (superClazz.getPackage().getName().startsWith("com.yomahub.liteflow.core")) {
+				break;
+			}
+			if (superClazz.equals(Object.class)) {
+				return null;
+			}
+		}
+
+		for (NodeTypeEnum e : NodeTypeEnum.values()) {
+			if (e.getMappingClazz().equals(superClazz)) {
+				return e;
+			}
+		}
+		return null;
+	}
+
+	public static NodeTypeEnum guessType(Class<?> clazz) {
+		NodeTypeEnum nodeType = guessTypeBySuperClazz(clazz);
+		if (nodeType == null) {
+			//尝试从类声明处进行推断
+			LiteflowCmpDefine liteflowCmpDefine = clazz.getAnnotation(LiteflowCmpDefine.class);
+			if (liteflowCmpDefine != null) {
+				//类声明方式中@LiteflowMethod是无需设置nodeId的
+				//但是如果设置了,那么核心逻辑其实是取类上定义的id的
+				//这种可以运行,但是理解起来不大好理解,所以给出提示,建议不要这么做
+				boolean mixDefined = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
+					LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
+					if (liteflowMethod != null) {
+						return StrUtil.isNotBlank(liteflowMethod.nodeId());
+					} else {
+						return false;
+					}
+				});
+
+				if (mixDefined) {
+					LOG.warn("[[[WARNING!!!]]]The @liteflowMethod in the class[{}] defined by @liteflowCmpDefine should not configure the nodeId again!",
+							clazz.getName());
+				}
+
+
+				//在返回之前,还要对方法级别的@LiteflowMethod进行检查,如果存在方法上的类型与类上的不一致时,给予警告信息
+				AtomicReference<Method> differenceTypeMethod = new AtomicReference<>();
+				boolean hasDifferenceNodeType = Arrays.stream(clazz.getDeclaredMethods()).anyMatch(method -> {
+					LiteflowMethod liteflowMethod = AnnotationUtil.getAnnotation(method, LiteflowMethod.class);
+					if (liteflowMethod != null) {
+						if (!liteflowMethod.nodeType().equals(liteflowCmpDefine.value())) {
+							differenceTypeMethod.set(method);
+							return true;
+						} else {
+							return false;
+						}
+					} else {
+						return false;
+					}
+				});
+
+				//表示存在不一样的类型
+				if (hasDifferenceNodeType) {
+					LOG.warn("[[[WARNING!!!]]]The nodeType in @liteflowCmpDefine declared on the class[{}] does not match the nodeType in @liteflowMethod declared on the method[{}]!",
+							clazz.getName(), differenceTypeMethod.get().getName());
+				}
+
+				return liteflowCmpDefine.value();
+			}
+
+			//再尝试声明式组件这部分的推断
+			LiteflowMethod liteflowMethod = Arrays.stream(clazz.getDeclaredMethods()).map(
+					method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class)
+			).filter(Objects::nonNull).filter(lfMethod -> lfMethod.value().isMainMethod()).findFirst().orElse(null);
+
+			if (liteflowMethod != null) {
+				nodeType = liteflowMethod.nodeType();
+			}
+		}
+		return nodeType;
+	}
 }

+ 2 - 5
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/SQLXmlELParser.java

@@ -13,7 +13,6 @@ import com.yomahub.liteflow.property.LiteflowConfig;
 import com.yomahub.liteflow.property.LiteflowConfigGetter;
 import com.yomahub.liteflow.util.JsonUtil;
 
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -35,9 +34,9 @@ public class SQLXmlELParser extends ClassXmlFlowELParser {
 
 		try {
 			SQLParserVO sqlParserVO = null;
-			if(MapUtil.isNotEmpty((liteflowConfig.getRuleSourceExtDataMap()))){
+			if (MapUtil.isNotEmpty((liteflowConfig.getRuleSourceExtDataMap()))) {
 				sqlParserVO = BeanUtil.toBean(liteflowConfig.getRuleSourceExtDataMap(), SQLParserVO.class, CopyOptions.create());
-			}else if (StrUtil.isNotBlank(liteflowConfig.getRuleSourceExtData())){
+			} else if (StrUtil.isNotBlank(liteflowConfig.getRuleSourceExtData())) {
 				sqlParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), SQLParserVO.class);
 			}
 			if (Objects.isNull(sqlParserVO)) {
@@ -49,7 +48,6 @@ public class SQLXmlELParser extends ClassXmlFlowELParser {
 
 			// 初始化 JDBCHelper
 			JDBCHelper.init(sqlParserVO);
-
 		} catch (ELSQLException elsqlException) {
 			throw elsqlException;
 		} catch (Exception ex) {
@@ -63,7 +61,6 @@ public class SQLXmlELParser extends ClassXmlFlowELParser {
 		return JDBCHelper.getInstance().getElDataContent();
 	}
 
-
 	/**
 	 * 检查配置文件并设置默认值
 	 *

+ 78 - 10
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/util/JDBCHelper.java

@@ -3,8 +3,10 @@ package com.yomahub.liteflow.parser.sql.util;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.text.StrFormatter;
 import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.enums.NodeTypeEnum;
 import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
 import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
+import com.yomahub.liteflow.script.ScriptExecutor;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
@@ -13,6 +15,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.ServiceLoader;
 
 /**
  * jdbc 工具类
@@ -24,8 +27,12 @@ public class JDBCHelper {
 
 	private static final String SQL_PATTERN = "SELECT {},{} FROM {} ";
 
+	private static final String SCRIPT_SQL_PATTERN = "SELECT {},{},{},{},{} FROM {} ";
+
 	private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
-	private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}</flow>";
+	private static final String NODE_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\" language=\"{}\"><![CDATA[{}]]></node>";
+	private static final String NODES_XML_PATTERN = "<nodes>{}</nodes>";
+	private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
 	private static final Integer FETCH_SIZE_MAX = 1000;
 
 	private SQLParserVO sqlParserVO;
@@ -87,14 +94,8 @@ public class JDBCHelper {
 			rs = stmt.executeQuery();
 
 			while (rs.next()) {
-				String elData = rs.getString(elDataField);
-				if (StrUtil.isBlank(elData)) {
-					throw new ELSQLException(StrFormatter.format("{} table exist {} field value is empty", tableName, elDataField));
-				}
-				String chainName = rs.getString(chainNameField);
-				if (StrUtil.isBlank(elData)) {
-					throw new ELSQLException(StrFormatter.format("{} table exist {} field value is empty", tableName, elDataField));
-				}
+				String elData = getStringFromResultSet(rs, elDataField);
+				String chainName = getStringFromResultSet(rs, chainNameField);
 
 				result.add(StrFormatter.format(CHAIN_XML_PATTERN, chainName, elData));
 			}
@@ -106,7 +107,66 @@ public class JDBCHelper {
 		}
 
 		String chains = CollUtil.join(result, StrUtil.CRLF);
-		return StrFormatter.format(XML_PATTERN, chains);
+		// 根据 SPI 判断是否需要添加 script node 节点
+		ServiceLoader<ScriptExecutor> loader = ServiceLoader.load(ScriptExecutor.class);
+		if (loader.iterator().hasNext()) {
+			String nodes = getScriptNodes();
+			return StrFormatter.format(XML_PATTERN, StrFormatter.format(NODES_XML_PATTERN, nodes), chains);
+		}
+
+		return StrFormatter.format(XML_PATTERN, StrUtil.EMPTY, chains);
+	}
+
+	public String getScriptNodes() {
+		List<String> result = new ArrayList<>();
+		Connection conn = null;
+		PreparedStatement stmt = null;
+		ResultSet rs = null;
+
+		String scriptNodeTableName = sqlParserVO.getScriptNodeTableName();
+		String scriptNodeIdField = sqlParserVO.getScriptNodeIdField();
+		String scriptNodeDataField = sqlParserVO.getScriptNodeDataField();
+		String scriptNodeNameField = sqlParserVO.getScriptNodeNameField();
+		String scriptNodeLanguageField = sqlParserVO.getScriptNodeLanguageField();
+		String scriptNodeTypeField = sqlParserVO.getScriptNodeTypeField();
+
+
+		String sqlCmd = StrFormatter.format(
+				SCRIPT_SQL_PATTERN,
+				scriptNodeIdField,
+				scriptNodeDataField,
+				scriptNodeNameField,
+				scriptNodeLanguageField,
+				scriptNodeTypeField,
+				scriptNodeTableName
+		);
+		try {
+			conn = getConn();
+			stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+			// 设置游标拉取数量
+			stmt.setFetchSize(FETCH_SIZE_MAX);
+			rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				String id = getStringFromResultSet(rs, scriptNodeIdField);
+				String data = getStringFromResultSet(rs, scriptNodeDataField);
+				String name = getStringFromResultSet(rs, scriptNodeNameField);
+				String type = getStringFromResultSet(rs, scriptNodeTypeField);
+				String language = getStringFromResultSet(rs, scriptNodeLanguageField);
+
+				if (!NodeTypeEnum.isScriptNodeType(type)) {
+					throw new ELSQLException("is not script node type; node id: " + id);
+				}
+
+				result.add(StrFormatter.format(NODE_XML_PATTERN, id, name, type, language, data));
+			}
+		} catch (Exception e) {
+			throw new ELSQLException(e.getMessage());
+		} finally {
+			// 关闭连接
+			close(conn, stmt, rs);
+		}
+		return CollUtil.join(result, StrUtil.CRLF);
 	}
 
 	/**
@@ -145,6 +205,14 @@ public class JDBCHelper {
 
 
 	//#region get set method
+	private String getStringFromResultSet(ResultSet rs, String field) throws SQLException {
+		String data = rs.getString(field);
+		if (StrUtil.isBlank(data)) {
+			throw new ELSQLException(StrFormatter.format("exist {} field value is empty", field));
+		}
+		return data;
+	}
+
 	private SQLParserVO getSqlParserVO() {
 		return sqlParserVO;
 	}

+ 78 - 0
liteflow-rule-plugin/liteflow-rule-sql/src/main/java/com/yomahub/liteflow/parser/sql/vo/SQLParserVO.java

@@ -43,6 +43,36 @@ public class SQLParserVO {
 	 */
 	private String elDataField = "el_data";
 
+	/**
+	 * 脚本 node 表名
+	 */
+	private String scriptNodeTableName = "script_node_table";
+
+	/**
+	 * 脚本 node id 字段
+	 */
+	private String scriptNodeIdField = "script_node_id";
+
+	/**
+	 * 脚本 node name 字段
+	 */
+	private String scriptNodeNameField = "script_node_name";
+
+	/**
+	 * 脚本 node type 字段
+	 */
+	private String scriptNodeDataField = "script_node_data";
+
+	/**
+	 * 脚本 node type 字段
+	 */
+	private String scriptNodeTypeField = "script_node_type";
+
+	/**
+	 * 脚本 node language 字段
+	 */
+	private String scriptNodeLanguageField = "script_node_language";
+
 	public String getUrl() {
 		return url;
 	}
@@ -98,4 +128,52 @@ public class SQLParserVO {
 	public void setElDataField(String elDataField) {
 		this.elDataField = elDataField;
 	}
+
+	public String getScriptNodeTableName() {
+		return scriptNodeTableName;
+	}
+
+	public void setScriptNodeTableName(String scriptNodeTableName) {
+		this.scriptNodeTableName = scriptNodeTableName;
+	}
+
+	public String getScriptNodeIdField() {
+		return scriptNodeIdField;
+	}
+
+	public void setScriptNodeIdField(String scriptNodeIdField) {
+		this.scriptNodeIdField = scriptNodeIdField;
+	}
+
+	public String getScriptNodeNameField() {
+		return scriptNodeNameField;
+	}
+
+	public void setScriptNodeNameField(String scriptNodeNameField) {
+		this.scriptNodeNameField = scriptNodeNameField;
+	}
+
+	public String getScriptNodeDataField() {
+		return scriptNodeDataField;
+	}
+
+	public void setScriptNodeDataField(String scriptNodeDataField) {
+		this.scriptNodeDataField = scriptNodeDataField;
+	}
+
+	public String getScriptNodeTypeField() {
+		return scriptNodeTypeField;
+	}
+
+	public void setScriptNodeTypeField(String scriptNodeTypeField) {
+		this.scriptNodeTypeField = scriptNodeTypeField;
+	}
+
+	public String getScriptNodeLanguageField() {
+		return scriptNodeLanguageField;
+	}
+
+	public void setScriptNodeLanguageField(String scriptNodeLanguageField) {
+		this.scriptNodeLanguageField = scriptNodeLanguageField;
+	}
 }

+ 8 - 0
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/pom.xml

@@ -49,5 +49,13 @@
             <version>${h2.version}</version>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-script-groovy</artifactId>
+            <version>${revision}</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 </project>

+ 56 - 27
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/java/com/yomahub/liteflow/test/sql/SQLWithXmlELSpringbootTest.java

@@ -33,35 +33,64 @@ import java.sql.Statement;
 @EnableAutoConfiguration
 @ComponentScan({"com.yomahub.liteflow.test.sql.cmp"})
 public class SQLWithXmlELSpringbootTest extends BaseTest {
-    @Resource
-    private FlowExecutor flowExecutor;
+	@Resource
+	private FlowExecutor flowExecutor;
 
-    @Test
-    public void testSQLWithXml() {
-        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
-        Assert.assertEquals("a==>b==>c", response.getExecuteStepStr());
+	@Test
+	public void testSQLWithXml() {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+		Assert.assertEquals("a==>b==>c", response.getExecuteStepStr());
 
-        // 修改数据库
-        changeData();
+		// 修改数据库
+		changeData();
 
-        // 重新加载规则
-        flowExecutor.reloadRule();
-        Assert.assertEquals("a==>c==>b", flowExecutor.execute2Resp("chain1", "arg").getExecuteStepStr());
-    }
+		// 重新加载规则
+		flowExecutor.reloadRule();
+		Assert.assertEquals("a==>c==>b", flowExecutor.execute2Resp("chain1", "arg").getExecuteStepStr());
+	}
 
-    /**
-     * 修改数据库数据
-     */
-    private void changeData() {
-        LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
-        SQLParserVO sqlParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), SQLParserVO.class);
-        Connection connection = null;
-        try {
-            connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
-            Statement statement = connection.createStatement();
-            statement.executeUpdate("UPDATE EL_TABLE SET EL_DATA='THEN(a, c, b);' WHERE chain_name='chain1'");
-        } catch (SQLException e) {
-            throw new ELSQLException(e.getMessage());
-        }
-    }
+	@Test
+	public void testSQLWithScriptXml() {
+		LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
+		Assert.assertTrue(response.isSuccess());
+		Assert.assertEquals("x0[if 脚本]==>a==>b", response.getExecuteStepStrWithoutTime());
+
+		// 修改数据库
+		changeScriptData();
+		// 重新加载规则
+		flowExecutor.reloadRule();
+		Assert.assertEquals("x0[if 脚本]", flowExecutor.execute2Resp("chain3", "arg").getExecuteStepStr());
+	}
+
+	/**
+	 * 修改数据库数据
+	 */
+	private void changeData() {
+		LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
+		SQLParserVO sqlParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), SQLParserVO.class);
+		Connection connection = null;
+		try {
+			connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
+			Statement statement = connection.createStatement();
+			statement.executeUpdate("UPDATE EL_TABLE SET EL_DATA='THEN(a, c, b);' WHERE chain_name='chain1'");
+		} catch (SQLException e) {
+			throw new ELSQLException(e.getMessage());
+		}
+	}
+
+	/**
+	 * 修改数据库数据
+	 */
+	private void changeScriptData() {
+		LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
+		SQLParserVO sqlParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), SQLParserVO.class);
+		Connection connection = null;
+		try {
+			connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
+			Statement statement = connection.createStatement();
+			statement.executeUpdate("UPDATE SCRIPT_NODE_TABLE SET SCRIPT_NODE_DATA='return false;' WHERE SCRIPT_NODE_ID='x0'");
+		} catch (SQLException e) {
+			throw new ELSQLException(e.getMessage());
+		}
+	}
 }

+ 1 - 1
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/resources/application-xml.properties

@@ -1,4 +1,4 @@
-liteflow.rule-source-ext-data={"url":"jdbc:h2:mem:test_db;MODE=MySQL","driverClassName":"org.h2.Driver","username":"root","password":"123456","tableName":"EL_TABLE","chainNameField":"chain_name","elDataField":"EL_DATA"}
+liteflow.rule-source-ext-data={"url":"jdbc:h2:mem:test_db;MODE=MySQL","driverClassName":"org.h2.Driver","username":"root","password":"123456","tableName":"EL_TABLE","chainNameField":"chain_name","elDataField":"EL_DATA","scriptNodeTableName":"script_node_table","scriptNodeIdField":"script_node_id","scriptNodeNameField":"script_node_name","scriptNodeDataField":"script_node_data","scriptNodeTypeField":"script_node_type","scriptNodeLanguageField":"script_node_language"}
 
 spring.datasource.driver-class-name=org.h2.Driver
 spring.datasource.url=jdbc:h2:mem:test_db;MODE=MySQL

+ 7 - 1
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/resources/sql/data.sql

@@ -1,4 +1,10 @@
 DELETE FROM EL_TABLE;
 
 INSERT INTO EL_TABLE (CHAIN_NAME,EL_DATA) values ('chain1','THEN(a, b, c);');
-INSERT INTO EL_TABLE (CHAIN_NAME,EL_DATA) values ('chain2','THEN(a, b, c);');
+INSERT INTO EL_TABLE (CHAIN_NAME,EL_DATA) values ('chain2','THEN(a, b, c);');
+INSERT INTO EL_TABLE (CHAIN_NAME,EL_DATA) values ('chain3','IF(x0, THEN(a, b));');
+
+DELETE FROM SCRIPT_NODE_TABLE;
+
+INSERT INTO SCRIPT_NODE_TABLE (SCRIPT_NODE_ID,SCRIPT_NODE_NAME,SCRIPT_NODE_TYPE,SCRIPT_NODE_LANGUAGE,SCRIPT_NODE_DATA) values ('x0','if 脚本','if_script','js','return true');
+INSERT INTO SCRIPT_NODE_TABLE (SCRIPT_NODE_ID,SCRIPT_NODE_NAME,SCRIPT_NODE_TYPE,SCRIPT_NODE_LANGUAGE,SCRIPT_NODE_DATA) values ('x1','if 脚本','if_script','js','return false');

+ 18 - 6
liteflow-testcase-el/liteflow-testcase-el-sql-springboot/src/test/resources/sql/schema.sql

@@ -1,6 +1,18 @@
-create table `EL_TABLE` (
-       `id` bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-       `chain_name` varchar(32) NOT NULL,
-       `el_data` varchar(1024) NOT NULL,
-       PRIMARY KEY (`id`)
-) ;
+create table `EL_TABLE`
+(
+    `id`         bigint        NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    `chain_name` varchar(32)   NOT NULL,
+    `el_data`    varchar(1024) NOT NULL,
+    PRIMARY KEY (`id`)
+);
+
+create table `script_node_table`
+(
+    `id`                   bigint        NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    `script_node_id`       varchar(32)   NOT NULL,
+    `script_node_name`     varchar(32)   NOT NULL,
+    `script_node_type`     varchar(32)   NOT NULL,
+    `script_node_language` varchar(32)   NOT NULL,
+    `script_node_data`     varchar(1024) NOT NULL,
+    PRIMARY KEY (`id`)
+);