enhancement #ID8XF9 对QLExpress4的支持

This commit is contained in:
everywhere.z
2025-11-28 19:40:05 +08:00
parent ad9906584a
commit e0c6f39a01
5 changed files with 28 additions and 34 deletions

View File

@@ -1,7 +1,6 @@
package com.yomahub.liteflow.builder.el; package com.yomahub.liteflow.builder.el;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
@@ -15,7 +14,7 @@ import com.alibaba.qlexpress4.exception.QLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.yomahub.liteflow.builder.el.operator.*;
import com.yomahub.liteflow.common.ChainConstant; import com.yomahub.liteflow.common.ChainConstant;
import com.yomahub.liteflow.common.entity.ValidationResp; import com.yomahub.liteflow.common.entity.ValidationResp;
import com.yomahub.liteflow.enums.ParseModeEnum; import com.yomahub.liteflow.enums.ParseModeEnum;
@@ -37,9 +36,9 @@ import com.yomahub.liteflow.util.ElRegexUtil;
import com.yomahub.liteflow.util.QlExpressUtils; import com.yomahub.liteflow.util.QlExpressUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
/** /**
@@ -73,7 +72,7 @@ public class LiteFlowChainELBuilder {
/** /**
* EL解析引擎 * EL解析引擎
*/ */
private final static Express4Runner EXPRESS_RUNNER = QlExpressUtils.getInstance(); private final static Express4Runner EXPRESS_RUNNER = QlExpressUtils.getELExpressRunner();
public static LiteFlowChainELBuilder createChain() { public static LiteFlowChainELBuilder createChain() {
return new LiteFlowChainELBuilder(); return new LiteFlowChainELBuilder();
@@ -290,25 +289,15 @@ public class LiteFlowChainELBuilder {
String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s", String msg = String.format("[node/chain is not exist or node/chain not register]\n EL: %s",
StrUtil.trim(elStr)); StrUtil.trim(elStr));
try { try {
// QLExpress4 暂时不支持 getInstructionSetFromLocalCache 方法 // 使用 QLExpress4 的 getOutVarNames 方法获取脚本中使用的所有外部变量
// 这里简化处理,直接返回基本错误信息 Set<String> outVarNames = EXPRESS_RUNNER.getOutVarNames(elStr);
// TODO: 等待 QLExpress4 提供相应的 API 后再完善此功能 if (CollUtil.isEmpty(outVarNames)) {
return msg;
/* 旧版本的代码,等待 QLExpress4 支持后再启用
InstructionSet parseResult = EXPRESS_RUNNER.getInstructionSetFromLocalCache(elStr);
if (parseResult == null) {
return msg;
}
String[] outAttrNames = parseResult.getOutAttrNames();
if (ArrayUtil.isEmpty(outAttrNames)) {
return msg; return msg;
} }
List<String> chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true); List<String> chainIds = CollUtil.map(FlowBus.getChainMap().values(), Chain::getChainId, true);
List<String> nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true); List<String> nodeIds = CollUtil.map(FlowBus.getNodeMap().values(), Node::getId, true);
for (String attrName : outAttrNames) { for (String attrName : outVarNames) {
if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) { if (!chainIds.contains(attrName) && !nodeIds.contains(attrName)) {
msg = String.format( msg = String.format(
"[%s] is not exist or [%s] is not registered, you need to define a node or chain with id [%s] and register it \n EL: ", "[%s] is not exist or [%s] is not registered, you need to define a node or chain with id [%s] and register it \n EL: ",
@@ -332,13 +321,12 @@ public class LiteFlowChainELBuilder {
// 还有一种特殊情况,就是 EL 表达式中的节点使用 node("a") // 还有一种特殊情况,就是 EL 表达式中的节点使用 node("a")
int nodeIndex = sourceEl.indexOf(String.format("node(\"%s\")", attrName)); int nodeIndex = sourceEl.indexOf(String.format("node(\"%s\")", attrName));
if (nodeIndex != -1) { if (nodeIndex != -1) {
// 需要加上 "EL: " 的长度 4再加上 node(" 长度 6再加上 "^" 的长度 1indexOf 从 0 // 需要加上 "EL: " 的长度 4再加上 "node("" 长度 6再加上 "^" 的长度 1indexOf 从 0
// 开始,所以还需要加 1 // 开始,所以还需要加 1
return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 12, true); return msg + sourceEl + "\n" + StrUtil.fill("^", CharUtil.SPACE, commaLeftIndex + 12, true);
} }
} }
} }
*/
} catch (Exception ex) { } catch (Exception ex) {
// ignore // ignore
} }
@@ -373,12 +361,8 @@ public class LiteFlowChainELBuilder {
// 只有当PARSE_ONE_ON_FIRST_EXEC时才会执行这个方法 // 只有当PARSE_ONE_ON_FIRST_EXEC时才会执行这个方法
// 那么会有一种级联的情况这个EL中含有其他的chain如果这时候不先解析其他chain就到导致诸如循环场景无法设置index或者obj的情况 // 那么会有一种级联的情况这个EL中含有其他的chain如果这时候不先解析其他chain就到导致诸如循环场景无法设置index或者obj的情况
// 所以这里要判断表达式里有没有其他的chain如果有进行先行解析 // 所以这里要判断表达式里有没有其他的chain如果有进行先行解析
Set<String> itemSet = EXPRESS_RUNNER.getOutVarNames(chain.getEl());
// TODO: QLExpress4 暂时没有 getOutVarNames 方法,这里先注释掉级联解析逻辑 itemSet.stream().forEach(item -> {
// 等待 QLExpress4 提供相应的 API 后再恢复
/*
String[] itemArray = EXPRESS_RUNNER.getOutVarNames(chain.getEl());
Arrays.stream(itemArray).forEach(item -> {
if (FlowBus.containChain(item) && !chain.getChainId().equals(item)) { if (FlowBus.containChain(item) && !chain.getChainId().equals(item)) {
Chain itemChain = FlowBus.getChain(item); Chain itemChain = FlowBus.getChain(item);
if (!itemChain.isCompiled()){ if (!itemChain.isCompiled()){
@@ -386,7 +370,6 @@ public class LiteFlowChainELBuilder {
} }
} }
}); });
*/
// 解析el成为一个Condition // 解析el成为一个Condition
// 为什么这里只是一个Condition而不是一个List<Condition>呢 // 为什么这里只是一个Condition而不是一个List<Condition>呢

View File

@@ -28,7 +28,7 @@ import java.util.stream.IntStream;
*/ */
public class LiteflowContextRegexMatcher { public class LiteflowContextRegexMatcher {
private static final Express4Runner expressRunner = new Express4Runner(InitOptions.DEFAULT_OPTIONS); private static final Express4Runner expressRunner = QlExpressUtils.getContextSearchExpressRunner();
public static Object searchContext(List<Tuple> contextList, String regPattern){ public static Object searchContext(List<Tuple> contextList, String regPattern){
// 把上下文数据转换成map形式的key为别名value为上下文 // 把上下文数据转换成map形式的key为别名value为上下文

View File

@@ -2,6 +2,7 @@ package com.yomahub.liteflow.util;
import com.alibaba.qlexpress4.Express4Runner; import com.alibaba.qlexpress4.Express4Runner;
import com.alibaba.qlexpress4.InitOptions; import com.alibaba.qlexpress4.InitOptions;
import com.alibaba.qlexpress4.security.QLSecurityStrategy;
import com.yomahub.liteflow.builder.el.operator.*; import com.yomahub.liteflow.builder.el.operator.*;
import com.yomahub.liteflow.common.ChainConstant; import com.yomahub.liteflow.common.ChainConstant;
@@ -18,6 +19,11 @@ public class QlExpressUtils {
*/ */
private final static Express4Runner EXPRESS_RUNNER = new Express4Runner(InitOptions.DEFAULT_OPTIONS); private final static Express4Runner EXPRESS_RUNNER = new Express4Runner(InitOptions.DEFAULT_OPTIONS);
/**
* 上下文搜索解析引擎
*/
private final static Express4Runner CONTEXT_SEARCH_EXPRESS_RUNNER = new Express4Runner(InitOptions.builder().securityStrategy(QLSecurityStrategy.open()).build());
static { static {
// 初始化QLExpress的Runner // 初始化QLExpress的Runner
EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.THEN, new ThenOperator()); EXPRESS_RUNNER.addVarArgsFunction(ChainConstant.THEN, new ThenOperator());
@@ -63,10 +69,17 @@ public class QlExpressUtils {
/** /**
* 获取QLExpress的实例 * 获取QLExpress的实例
*/ */
public static Express4Runner getInstance() { public static Express4Runner getELExpressRunner() {
return EXPRESS_RUNNER; return EXPRESS_RUNNER;
} }
/**
* 获取上下文搜索的QLExpress实例
*/
public static Express4Runner getContextSearchExpressRunner() {
return CONTEXT_SEARCH_EXPRESS_RUNNER;
}
/** /**
* 检查变量名是否符合 变量命名规则 * 检查变量名是否符合 变量命名规则
* *

View File

@@ -8,7 +8,6 @@ import com.yomahub.liteflow.parser.sql.read.AbstractSqlRead;
import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO; import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil; import com.yomahub.liteflow.parser.sql.util.LiteFlowJdbcUtil;
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO; import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
import org.apache.commons.lang.StringUtils;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -56,7 +55,7 @@ public class ScriptRead extends AbstractSqlRead<ScriptVO> {
@Override @Override
public String buildQuerySql() { public String buildQuerySql() {
if (StringUtils.isNotBlank(super.config.getScriptCustomSql())) { if (StrUtil.isNotBlank(super.config.getScriptCustomSql())) {
return super.config.getScriptCustomSql(); return super.config.getScriptCustomSql();
} }
@@ -72,7 +71,7 @@ public class ScriptRead extends AbstractSqlRead<ScriptVO> {
@Override @Override
public String buildQuerySql(String scriptNodeId) { public String buildQuerySql(String scriptNodeId) {
if (StringUtils.isNotBlank(super.config.getScriptCustomSql())) { if (StrUtil.isNotBlank(super.config.getScriptCustomSql())) {
return super.config.getScriptCustomSql(); return super.config.getScriptCustomSql();
} }

View File

@@ -16,7 +16,6 @@ import com.yomahub.liteflow.parser.sql.read.SqlReadFactory;
import com.yomahub.liteflow.parser.sql.read.vo.ChainVO; import com.yomahub.liteflow.parser.sql.read.vo.ChainVO;
import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO; import com.yomahub.liteflow.parser.sql.read.vo.ScriptVO;
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO; import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -116,7 +115,7 @@ public class JDBCHelper {
String language = scriptVO.getLanguage(); String language = scriptVO.getLanguage();
String elData = scriptVO.getScript(); String elData = scriptVO.getScript();
if (StringUtils.isNotBlank(scriptVO.getLanguage())) { if (StrUtil.isNotBlank(scriptVO.getLanguage())) {
scriptList.add(StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, language, elData)); scriptList.add(StrUtil.format(NODE_ITEM_WITH_LANGUAGE_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, language, elData));
} else { } else {
scriptList.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, elData)); scriptList.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, elData));