mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 04:02:09 +08:00
!342 enhancement #ICU4Z3 优化 nodeid 不合法报错提示,增加错误引导
Merge pull request !342 from 与或非/issues/ICU4Z3
This commit is contained in:
@@ -31,6 +31,7 @@ import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.util.ElRegexUtil;
|
||||
import com.yomahub.liteflow.util.QlExpressUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -66,53 +67,10 @@ public class LiteFlowChainELBuilder {
|
||||
* 所以在这里做一个缓存,等conditionList全部build完毕后,再去一次性替换chain里面的conditionList
|
||||
*/
|
||||
private final List<Condition> conditionList;
|
||||
|
||||
/**
|
||||
* EL解析引擎
|
||||
*/
|
||||
public final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
|
||||
static {
|
||||
// 初始化QLExpress的Runner
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.THEN, new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHEN, new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.SER, new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.PAR, new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.SWITCH, new SwitchOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.AND, new AndOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.OR, new OrOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NOT, new NotOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO.toLowerCase(), Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DEFAULT, Object.class, new DefaultOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TAG, Object.class, new TagOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ANY, Object.class, new AnyOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MUST, Object.class, new MustOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PERCENTAGE, Object.class, new PercentageOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_MILLISECONDS, Object.class, new MaxWaitMillisecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PARALLEL, Object.class, new ParallelOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.RETRY, Object.class, new RetryOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BIND, Object.class, new BindOperator());
|
||||
|
||||
}
|
||||
/**
|
||||
* EL解析引擎
|
||||
*/
|
||||
private final static ExpressRunner EXPRESS_RUNNER = QlExpressUtils.getInstance();
|
||||
|
||||
public static LiteFlowChainELBuilder createChain() {
|
||||
return new LiteFlowChainELBuilder();
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* node id不合法异常
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.13.2
|
||||
*/
|
||||
public class NodeIdUnIllegalException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public NodeIdUnIllegalException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.yomahub.liteflow.enums.FlowParserTypeEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.ParseModeEnum;
|
||||
import com.yomahub.liteflow.exception.ComponentCannotRegisterException;
|
||||
import com.yomahub.liteflow.exception.NodeIdUnIllegalException;
|
||||
import com.yomahub.liteflow.exception.NullNodeTypeException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
@@ -43,6 +44,7 @@ import com.yomahub.liteflow.spi.ContextAware;
|
||||
import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
|
||||
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
||||
import com.yomahub.liteflow.util.CopyOnWriteHashMap;
|
||||
import com.yomahub.liteflow.util.QlExpressUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -303,6 +305,14 @@ public class FlowBus {
|
||||
// 调用到这里,分两种情况,一是脚本组件,二是通过LiteFlowNodeBuilder代码进行组装的组件
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script, String language) {
|
||||
try {
|
||||
String nodeIdStr = StrUtil.isBlank(nodeId) ? name : nodeId;
|
||||
// 检查nodeId是否合法
|
||||
boolean nodeIdFlag = QlExpressUtils.checkVariableName(nodeIdStr);
|
||||
// node id 不合法
|
||||
if (!nodeIdFlag) {
|
||||
throw new NodeIdUnIllegalException(nodeIdStr);
|
||||
}
|
||||
|
||||
// 获得初始化好的NodeComponent
|
||||
// 按理说一个nodeId对应一个NodeComponent,这里得到的是List<NodeComponent>的原因是,声明式组件有可能会有多个nodeId。
|
||||
// 声明式组件又分类声明和方法声明,如果对于方法声明来说,这里的nodeId其实并不是最终真正的nodeId。
|
||||
@@ -314,7 +324,22 @@ public class FlowBus {
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
addCompiledNode2Map(nodes.get(i), nodeId, script, language, type, cmpInstanceList.get(i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (NodeIdUnIllegalException e) {
|
||||
String nodeIdStr = e.getMessage();
|
||||
String error = StrUtil.format(
|
||||
"component[{}] register error",
|
||||
StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name)
|
||||
);
|
||||
|
||||
error = "Invalid node id: [" + nodeIdStr + "]. "
|
||||
+ "node id must follow variable naming rules: "
|
||||
+ "cannot start with a digit, must consist of letters, digits, underscores (_), or dollar signs ($), "
|
||||
+ "and must not contain hyphens (-). "
|
||||
+ error;
|
||||
|
||||
LOG.error(error, e);
|
||||
throw new ComponentCannotRegisterException(StrUtil.format("{} {}", error, e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name) ? nodeId : StrUtil.format("{}({})", nodeId, name));
|
||||
LOG.error(e.getMessage());
|
||||
throw new ComponentCannotRegisterException(StrUtil.format("{} {}", error, e.getMessage()));
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.yomahub.liteflow.util;
|
||||
|
||||
import com.ql.util.express.ExpressRunner;
|
||||
import com.yomahub.liteflow.builder.el.operator.*;
|
||||
import com.yomahub.liteflow.common.ChainConstant;
|
||||
|
||||
/**
|
||||
* EL 工具类
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.13.2
|
||||
*/
|
||||
public class QlExpressUtils {
|
||||
|
||||
/**
|
||||
* EL解析引擎
|
||||
*/
|
||||
private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
|
||||
static {
|
||||
// 初始化QLExpress的Runner
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.THEN, new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHEN, new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.SER, new ThenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.PAR, new WhenOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.SWITCH, new SwitchOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.AND, new AndOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.OR, new OrOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NOT, new NotOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO.toLowerCase(), Object.class, new ToOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DEFAULT, Object.class, new DefaultOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TAG, Object.class, new TagOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ANY, Object.class, new AnyOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MUST, Object.class, new MustOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PERCENTAGE, Object.class, new PercentageOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_MILLISECONDS, Object.class, new MaxWaitMillisecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PARALLEL, Object.class, new ParallelOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.RETRY, Object.class, new RetryOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BIND, Object.class, new BindOperator());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取QLExpress的实例
|
||||
*/
|
||||
public static ExpressRunner getInstance() {
|
||||
return EXPRESS_RUNNER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查变量名是否符合 变量命名规则
|
||||
*
|
||||
* @param variableName 变量名
|
||||
* @return 如果符合规范返回 true,否则返回 false
|
||||
*/
|
||||
public static boolean checkVariableName(String variableName) {
|
||||
if (variableName == null || variableName.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 首字符必须是合法的 Java 标识符起始字符
|
||||
if (!Character.isJavaIdentifierStart(variableName.charAt(0))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 后续字符必须是合法的 Java 标识符部分
|
||||
for (int i = 1; i < variableName.length(); i++) {
|
||||
if (!Character.isJavaIdentifierPart(variableName.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.yomahub.liteflow.test.utils;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.yomahub.liteflow.util.QlExpressUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* EL 工具类测试
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.13.2
|
||||
*/
|
||||
public class QlExpressUtilsTest {
|
||||
|
||||
@Test
|
||||
public void checkVariableNameTest(){
|
||||
// 错误的
|
||||
Assert.isFalse(QlExpressUtils.checkVariableName(""));
|
||||
Assert.isFalse(QlExpressUtils.checkVariableName("11a"));
|
||||
Assert.isFalse(QlExpressUtils.checkVariableName("a-a"));
|
||||
// 正确的
|
||||
Assert.isTrue(QlExpressUtils.checkVariableName("aa"));
|
||||
Assert.isTrue(QlExpressUtils.checkVariableName("_aa"));
|
||||
Assert.isTrue(QlExpressUtils.checkVariableName("$aa"));
|
||||
Assert.isTrue(QlExpressUtils.checkVariableName("$a_a"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user