bug #IC8UPJ 规则EL校验在liteflow.parse-mode=PARSE_ONE_ON_FIRST_EXEC时失效

This commit is contained in:
everywhere.z
2025-05-21 17:58:07 +08:00
parent 65cbc664b7
commit 535c2b7c84
3 changed files with 44 additions and 32 deletions

View File

@@ -146,13 +146,7 @@ public class LiteFlowChainELBuilder {
}
List<String> errorList = new ArrayList<>();
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 往上下文里放入所有的node使得el表达式可以直接引用到nodeId
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId)));
// 解析route el成为一个executable
Executable routeExecutable = (Executable) EXPRESS_RUNNER.execute(routeEl, context, errorList, true, true);
Executable routeExecutable = compile(routeEl, errorList, false);
// 判断routeEL是不是符合规范
if (!(routeExecutable instanceof AndOrCondition || routeExecutable instanceof NotCondition || routeExecutable instanceof Node)){
@@ -197,22 +191,7 @@ public class LiteFlowChainELBuilder {
List<String> errorList = new ArrayList<>();
try {
DefaultContext<String, Object> context = new DefaultContext<>();
// 这里一定要先放chain再放node因为node优先于chain所以当重名时node会覆盖掉chain
// 往上下文里放入所有的chain是的el表达式可以直接引用到chain
FlowBus.getChainMap().values().forEach(chain -> context.put(chain.getChainId(), chain));
// 往上下文里放入所有的node使得el表达式可以直接引用到nodeId
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId)));
// 放入当前主chain的ID
context.put(ChainConstant.CURR_CHAIN_ID, this.chain.getChainId());
// 解析el成为一个Condition
// 为什么这里只是一个Condition而不是一个List<Condition>呢
// 这里无论多复杂的外面必定有一个最外层的Condition所以这里只有一个内部可以嵌套很多层这点和以前的不太一样
Condition condition = (Condition) EXPRESS_RUNNER.execute(elStr, context, errorList, true, true);
Condition condition = compile(elStr, errorList, true);
if (Objects.isNull(condition)){
throw new QLException(StrUtil.format("parse el fail,el:[{}]", elStr));
@@ -269,7 +248,6 @@ public class LiteFlowChainELBuilder {
* @param elStr EL表达式
* @return true 校验成功 false 校验失败
*/
@Deprecated
public static boolean validate(String elStr) {
return validateWithEx(elStr).isSuccess();
}
@@ -277,16 +255,16 @@ public class LiteFlowChainELBuilder {
/**
* 校验
*
* @param elStr
* @return
* @param elStr EL表达式
* @return ValidationResp
*/
public static ValidationResp validateWithEx(String elStr) {
try {
LiteFlowChainELBuilder.createChain().setEL(elStr);
LiteFlowChainELBuilder.createChain().compile(elStr, null, true);
return ValidationResp.success();
} catch (Exception e) {
LOG.error("validate error", e);
return ValidationResp.fail(e);
String msg = buildDataNotFoundExceptionMsg(elStr);
return ValidationResp.fail(new ELParseException(msg));
}
}
@@ -460,4 +438,29 @@ public class LiteFlowChainELBuilder {
}
}
@SuppressWarnings("unchecked")
private <T extends Executable> T compile(String elStr, List<String> errorList, boolean putChain2Context) throws Exception{
DefaultContext<String, Object> context = new DefaultContext<>();
if (putChain2Context){
// 这里一定要先放chain再放node因为node优先于chain所以当重名时node会覆盖掉chain
// 往上下文里放入所有的chain是的el表达式可以直接引用到chain
FlowBus.getChainMap().values().forEach(chain -> context.put(chain.getChainId(), chain));
}
// 往上下文里放入所有的node使得el表达式可以直接引用到nodeId
FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.getNode(nodeId)));
// 放入当前主chain的ID
if (this.chain != null){
context.put(ChainConstant.CURR_CHAIN_ID, this.chain.getChainId());
}
// 解析el成为一个Condition
// 为什么这里只是一个Condition而不是一个List<Condition>呢
// 这里无论多复杂的外面必定有一个最外层的Condition所以这里只有一个内部可以嵌套很多层这点和以前的不太一样
return (T) EXPRESS_RUNNER.execute(elStr, context, errorList, true, true);
}
}

View File

@@ -2,8 +2,10 @@ package com.yomahub.liteflow.test.validateRule;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.common.entity.ValidationResp;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.url.LiteflowNodeELSpringbootTest;
import com.yomahub.liteflow.test.validateRule.cmp.ACmp;
import com.yomahub.liteflow.test.validateRule.cmp.BCmp;
import com.yomahub.liteflow.test.validateRule.cmp.CCmp;
@@ -11,13 +13,15 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
@TestPropertySource(value = "classpath:/validate/application.properties")
@SpringBootTest(classes = ValidateRuleELSpringbootTest.class)
@EnableAutoConfiguration
public class ValidateRuleELSpringbootTest extends BaseTest {
@Test
public void testChainELExpressValidate() {
public void testChainELExpressValidate1() {
LiteFlowNodeBuilder.createNode()
.setId("a")
.setName("组件A")
@@ -36,8 +40,12 @@ public class ValidateRuleELSpringbootTest extends BaseTest {
.setType(NodeTypeEnum.COMMON)
.setClazz(CCmp.class)
.build();
Assertions.assertFalse(LiteFlowChainELBuilder.validate("THEN(a, b, h)"));
Assertions.assertTrue(LiteFlowChainELBuilder.validate("THEN(a, b, c)"));
ValidationResp resp1 = LiteFlowChainELBuilder.validateWithEx("THEN(a, b, h)");
ValidationResp resp2 = LiteFlowChainELBuilder.validateWithEx("THEN(a, b, c)");
Assertions.assertFalse(resp1.isSuccess());
Assertions.assertTrue(resp2.isSuccess());
}
}

View File

@@ -0,0 +1 @@
liteflow.parse-mode=PARSE_ONE_ON_FIRST_EXEC