diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java index 4801cd876..f048d3066 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/LiteFlowChainELBuilder.java @@ -68,6 +68,7 @@ public class LiteFlowChainELBuilder { expressRunner.addFunctionAndClassMethod("to", Object.class, new ToOperator()); expressRunner.addFunctionAndClassMethod("tag", Object.class, new TagOperator()); expressRunner.addFunctionAndClassMethod("any", Object.class, new AnyOperator()); + expressRunner.addFunctionAndClassMethod("id", Object.class, new IdOperator()); expressRunner.addFunctionAndClassMethod("ignoreError", Object.class, new IgnoreErrorOperator()); expressRunner.addFunctionAndClassMethod("threadPool", Object.class, new ThreadPoolOperator()); } @@ -90,7 +91,7 @@ public class LiteFlowChainELBuilder { //往上下文里放入所有的node,使得el表达式可以直接引用到nodeId DefaultContext context = new DefaultContext<>(); FlowBus.getNodeMap().keySet().forEach(nodeId -> context.put(nodeId, FlowBus.copyNode(nodeId))); - Condition condition = (Condition) expressRunner.execute(elStr, context, errorList, false, false); + Condition condition = (Condition) expressRunner.execute(elStr, context, errorList, false, true); //从condition的第一层嵌套结构里拿出Pre和Finally节点 //为什么只寻找第一层,而不往下寻找了呢? diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ToOperator.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ToOperator.java index 7e93d6b46..4fa4d75c3 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ToOperator.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/el/operator/ToOperator.java @@ -24,7 +24,7 @@ public class ToOperator extends Operator { throw new Exception(); } - if (objects.length != 2){ + if (objects.length <= 2){ LOG.error("parameter error"); throw new Exception(); } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java index 58008990d..f3581daab 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java @@ -21,6 +21,7 @@ import com.yomahub.liteflow.flow.LiteflowResponse; import com.yomahub.liteflow.flow.element.Chain; import com.yomahub.liteflow.flow.element.Node; import com.yomahub.liteflow.parser.*; +import com.yomahub.liteflow.parser.el.*; import com.yomahub.liteflow.property.LiteflowConfig; import com.yomahub.liteflow.property.LiteflowConfigGetter; import com.yomahub.liteflow.slot.DataBus; @@ -196,6 +197,12 @@ public class FlowExecutor { return new LocalJsonFlowParser(); case TYPE_YML: return new LocalYmlFlowParser(); + case TYPE_EL_XML: + return new LocalXmlFlowELParser(); + case TYPE_EL_JSON: + return new LocalJsonFlowELParser(); + case TYPE_EL_YML: + return new LocalYmlFlowELParser(); default: } } else if (isClassConfig(path)) { @@ -208,6 +215,12 @@ public class FlowExecutor { return (JsonFlowParser) ContextAwareHolder.loadContextAware().registerBean(c); case TYPE_YML: return (YmlFlowParser) ContextAwareHolder.loadContextAware().registerBean(c); + case TYPE_EL_XML: + return (XmlFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c); + case TYPE_EL_JSON: + return (JsonFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c); + case TYPE_EL_YML: + return (YmlFlowELParser) ContextAwareHolder.loadContextAware().registerBean(c); default: } } else if (isZKConfig(path)) { @@ -219,6 +232,12 @@ public class FlowExecutor { return new ZookeeperJsonFlowParser(liteflowConfig.getZkNode()); case TYPE_YML: return new ZookeeperYmlFlowParser(liteflowConfig.getZkNode()); + case TYPE_EL_XML: + return new ZookeeperXmlFlowELParser(liteflowConfig.getZkNode()); + case TYPE_EL_JSON: + return new ZookeeperJsonFlowELParser(liteflowConfig.getZkNode()); + case TYPE_EL_YML: + return new ZookeeperYmlFlowELParser(liteflowConfig.getZkNode()); default: } } @@ -232,7 +251,10 @@ public class FlowExecutor { private boolean isLocalConfig(String path) { return ReUtil.isMatch(LOCAL_XML_CONFIG_REGEX, path) || ReUtil.isMatch(LOCAL_JSON_CONFIG_REGEX, path) - || ReUtil.isMatch(LOCAL_YML_CONFIG_REGEX, path); + || ReUtil.isMatch(LOCAL_YML_CONFIG_REGEX, path) + || ReUtil.isMatch(LOCAL_EL_XML_CONFIG_REGEX, path) + || ReUtil.isMatch(LOCAL_EL_JSON_CONFIG_REGEX, path) + || ReUtil.isMatch(LOCAL_EL_YML_CONFIG_REGEX, path); } /** @@ -268,7 +290,6 @@ public class FlowExecutor { } else if (isClassConfig(path)) { //其实整个这个判断块代码可以不要,因为如果是自定义配置源的话,标准写法也要在前面加xml:/json:/yml:这种 //但是这块可能是考虑到有些人忘加了,所以再来判断下。如果写了标准的话,是不会走到这块来的 - //不过el形式的已经不支持这块了,需要标准写法,这点注意 try { Class clazz = Class.forName(path); if (ClassXmlFlowParser.class.isAssignableFrom(clazz)) { @@ -277,6 +298,12 @@ public class FlowExecutor { return FlowParserTypeEnum.TYPE_JSON; } else if (ClassYmlFlowParser.class.isAssignableFrom(clazz)) { return FlowParserTypeEnum.TYPE_YML; + } else if (ClassXmlFlowELParser.class.isAssignableFrom(clazz)) { + return FlowParserTypeEnum.TYPE_EL_XML; + } else if (ClassJsonFlowELParser.class.isAssignableFrom(clazz)) { + return FlowParserTypeEnum.TYPE_EL_JSON; + } else if (ClassYmlFlowELParser.class.isAssignableFrom(clazz)) { + return FlowParserTypeEnum.TYPE_EL_YML; } } catch (ClassNotFoundException e) { LOG.error(e.getMessage()); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java index 697583273..940469ee5 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/Condition.java @@ -45,7 +45,7 @@ public abstract class Condition implements Executable{ @Override public String getExecuteName() { - return this.getExecuteType().name(); + return this.id; } public List getExecutableList() { diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java index a42fb09d9..330f40a1a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/flow/element/condition/WhenCondition.java @@ -145,7 +145,7 @@ public class WhenCondition extends Condition { //循环判断CompletableFuture的返回值,如果异步执行失败,则抛出相应的业务异常 for(WhenFutureObj whenFutureObj : allCompletableWhenFutureObjList){ if (!whenFutureObj.isSuccess()){ - LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].", whenFutureObj.getExecutorName(), slot.getRequestId())); + LOG.info(StrUtil.format("requestId [{}] when-executor[{}] execute failed. errorResume [false].",slot.getRequestId(), whenFutureObj.getExecutorName())); throw whenFutureObj.getEx(); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassJsonFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassJsonFlowELParser.java new file mode 100644 index 000000000..a1f8c46c3 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassJsonFlowELParser.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.parser.el; + +import com.yomahub.liteflow.parser.JsonFlowParser; + +import java.util.List; + +/** + * 基于自定义的json方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public abstract class ClassJsonFlowELParser extends JsonFlowParser { + @Override + public void parseMain(List pathList) throws Exception { + String content = parseCustom(); + parse(content); + } + + public abstract String parseCustom(); +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassXmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassXmlFlowELParser.java new file mode 100644 index 000000000..4898a920f --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassXmlFlowELParser.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.parser.el; + +import java.util.List; + +/** + * 基于自定义的xml方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public abstract class ClassXmlFlowELParser extends XmlFlowELParser{ + @Override + public void parseMain(List pathList) throws Exception { + String content = parseCustom(); + parse(content); + } + + public abstract String parseCustom(); +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassYmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassYmlFlowELParser.java new file mode 100644 index 000000000..ab9cd1d46 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ClassYmlFlowELParser.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.parser.el; + +import java.util.List; + +/** + * 基于自定义的yml方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public abstract class ClassYmlFlowELParser extends YmlFlowELParser { + @Override + public void parseMain(List pathList) throws Exception { + String content = parseCustom(); + parse(content); + } + + public abstract String parseCustom(); +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/JsonFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/JsonFlowELParser.java new file mode 100644 index 000000000..70a5534ae --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/JsonFlowELParser.java @@ -0,0 +1,130 @@ +package com.yomahub.liteflow.parser.el; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import com.yomahub.liteflow.builder.prop.NodePropBean; +import com.yomahub.liteflow.exception.ChainDuplicateException; +import com.yomahub.liteflow.flow.FlowBus; +import com.yomahub.liteflow.parser.BaseFlowParser; +import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import static com.yomahub.liteflow.common.ChainConstant.*; + +/** + * JSON形式的EL表达式解析抽象引擎 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public abstract class JsonFlowELParser extends BaseFlowParser { + + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); + + private final Set CHAIN_NAME_SET = new CopyOnWriteArraySet<>(); + + public void parse(String content) throws Exception { + parse(ListUtil.toList(content)); + } + + @Override + public void parse(List contentList) throws Exception { + if (CollectionUtil.isEmpty(contentList)) { + return; + } + + List jsonObjectList = ListUtil.toList(); + for (String content : contentList) { + //把字符串原生转换为json对象,如果不加第二个参数OrderedField,会无序 + JSONObject flowJsonObject = JSONObject.parseObject(content, Feature.OrderedField); + jsonObjectList.add(flowJsonObject); + } + + parseJsonObject(jsonObjectList); + } + + //json格式,解析过程 + public void parseJsonObject(List flowJsonObjectList) throws Exception { + //在相应的环境下进行节点的初始化工作 + //在spring体系下会获得spring扫描后的节点,接入元数据 + //在非spring体系下是一个空实现,等于不做此步骤 + ContextCmpInitHolder.loadContextCmpInit().initCmp(); + + //先在元数据里放上chain + //先放有一个好处,可以在parse的时候先映射到FlowBus的chainMap,然后再去解析 + //这样就不用去像之前的版本那样回归调用 + //同时也解决了不能循环依赖的问题 + flowJsonObjectList.forEach(jsonObject -> { + // 解析chain节点 + JSONArray chainArray = jsonObject.getJSONObject(FLOW).getJSONArray(CHAIN); + + //先在元数据里放上chain + chainArray.forEach(o -> { + JSONObject innerJsonObject = (JSONObject) o; + //校验加载的 chainName 是否有重复的 + //TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了 + String chainName = innerJsonObject.getString(NAME); + if (!CHAIN_NAME_SET.add(chainName)) { + throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName)); + } + + FlowBus.addChain(innerJsonObject.getString(NAME)); + }); + }); + // 清空 + CHAIN_NAME_SET.clear(); + + for (JSONObject flowJsonObject : flowJsonObjectList) { + // 当存在节点定义时,解析node节点 + if (flowJsonObject.getJSONObject(FLOW).containsKey(NODES)) { + JSONArray nodeArrayList = flowJsonObject.getJSONObject(FLOW).getJSONObject(NODES).getJSONArray(NODE); + String id, name, clazz, script, type, file; + for (int i = 0; i < nodeArrayList.size(); i++) { + JSONObject nodeObject = nodeArrayList.getJSONObject(i); + id = nodeObject.getString(ID); + name = nodeObject.getString(NAME); + clazz = nodeObject.getString(_CLASS); + type = nodeObject.getString(TYPE); + script = nodeObject.getString(VALUE); + file = nodeObject.getString(FILE); + + // 构建 node + NodePropBean nodePropBean = new NodePropBean() + .setId(id) + .setName(name) + .setClazz(clazz) + .setScript(script) + .setType(type) + .setFile(file); + + buildNode(nodePropBean); + } + } + + //解析每一个chain + JSONArray chainArray = flowJsonObject.getJSONObject(FLOW).getJSONArray(CHAIN); + chainArray.forEach(o -> { + JSONObject jsonObject = (JSONObject) o; + parseOneChain(jsonObject); + }); + } + } + + + /** + * 解析一个chain的过程 + */ + private void parseOneChain(JSONObject chainObject) { + //构建chainBuilder + String chainName = chainObject.getString(NAME); + String el = chainObject.getString(VALUE); + LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName); + chainELBuilder.setEL(el).build(); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java new file mode 100644 index 000000000..c343b37c6 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java @@ -0,0 +1,19 @@ +package com.yomahub.liteflow.parser.el; + +import com.yomahub.liteflow.spi.holder.PathContentParserHolder; + +import java.util.List; + +/** + * 基于本地的json方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public class LocalJsonFlowELParser extends JsonFlowELParser { + + @Override + public void parseMain(List pathList) throws Exception { + List contentList = PathContentParserHolder.loadContextAware().parseContent(pathList); + parse(contentList); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalXmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalXmlFlowELParser.java new file mode 100644 index 000000000..d0769f164 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalXmlFlowELParser.java @@ -0,0 +1,18 @@ +package com.yomahub.liteflow.parser.el; + +import com.yomahub.liteflow.spi.holder.PathContentParserHolder; + +import java.util.List; + +/** + * 基于本地的xml方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public class LocalXmlFlowELParser extends XmlFlowELParser{ + @Override + public void parseMain(List pathList) throws Exception { + List contentList = PathContentParserHolder.loadContextAware().parseContent(pathList); + parse(contentList); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalYmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalYmlFlowELParser.java new file mode 100644 index 000000000..8c85abef7 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalYmlFlowELParser.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.parser.el; + +import com.yomahub.liteflow.spi.holder.PathContentParserHolder; + +import java.util.List; + +/** + * 基于本地的yml方式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public class LocalYmlFlowELParser extends YmlFlowELParser { + + @Override + public void parseMain(List pathList) throws Exception { + List contentList = PathContentParserHolder.loadContextAware().parseContent(pathList); + parse(contentList); + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ELXmlFlowParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/XmlFlowELParser.java similarity index 72% rename from liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ELXmlFlowParser.java rename to liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/XmlFlowELParser.java index faaca1230..c11548ac2 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ELXmlFlowParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/XmlFlowELParser.java @@ -3,10 +3,8 @@ package com.yomahub.liteflow.parser.el; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjectUtil; -import com.yomahub.liteflow.builder.LiteFlowChainBuilder; -import com.yomahub.liteflow.builder.prop.ChainPropBean; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; import com.yomahub.liteflow.builder.prop.NodePropBean; -import com.yomahub.liteflow.enums.ConditionTypeEnum; import com.yomahub.liteflow.exception.ChainDuplicateException; import com.yomahub.liteflow.flow.FlowBus; import com.yomahub.liteflow.parser.BaseFlowParser; @@ -18,22 +16,20 @@ import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import static com.yomahub.liteflow.common.ChainConstant.*; -import static com.yomahub.liteflow.common.ChainConstant.THREAD_EXECUTOR_CLASS; /** - * EL表达引擎Xml形式的解析抽象引擎 + * Xml形式的EL表达式解析抽象引擎 * @author Bryan.Zhang * @since 2.8.0 */ -public abstract class ELXmlFlowParser extends BaseFlowParser { +public abstract class XmlFlowELParser extends BaseFlowParser { - private final Logger LOG = LoggerFactory.getLogger(XmlFlowParser.class); + private final Logger LOG = LoggerFactory.getLogger(this.getClass()); private final Set CHAIN_NAME_SET = new CopyOnWriteArraySet<>(); @@ -122,36 +118,10 @@ public abstract class ELXmlFlowParser extends BaseFlowParser { * 解析一个chain的过程 */ private void parseOneChain(Element e) { - String condValueStr; - String group; - String errorResume; - String any; - String threadExecutorClass; - ConditionTypeEnum conditionType; - //构建chainBuilder String chainName = e.attributeValue(NAME); - LiteFlowChainBuilder chainBuilder = LiteFlowChainBuilder.createChain().setChainName(chainName); - - for (Iterator it = e.elementIterator(); it.hasNext(); ) { - Element condE = it.next(); - conditionType = ConditionTypeEnum.getEnumByCode(condE.getName()); - condValueStr = condE.attributeValue(VALUE); - errorResume = condE.attributeValue(ERROR_RESUME); - group = condE.attributeValue(GROUP); - any = condE.attributeValue(ANY); - threadExecutorClass = condE.attributeValue(THREAD_EXECUTOR_CLASS); - - ChainPropBean chainPropBean = new ChainPropBean() - .setCondValueStr(condValueStr) - .setGroup(group) - .setErrorResume(errorResume) - .setAny(any) - .setThreadExecutorClass(threadExecutorClass) - .setConditionType(conditionType); - - // 构建 chain - buildChain(chainPropBean, chainBuilder); - } + String el = e.getTextTrim(); + LiteFlowChainELBuilder chainELBuilder = LiteFlowChainELBuilder.createChain().setChainName(chainName); + chainELBuilder.setEL(el).build(); } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/YmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/YmlFlowELParser.java new file mode 100644 index 000000000..db18da196 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/YmlFlowELParser.java @@ -0,0 +1,49 @@ +package com.yomahub.liteflow.parser.el; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.yomahub.liteflow.parser.JsonFlowParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +import java.util.List; +import java.util.Map; + +/** + * yml形式的EL表达式解析抽象引擎 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public abstract class YmlFlowELParser extends JsonFlowELParser { + + private final Logger LOG = LoggerFactory.getLogger(YmlFlowELParser.class); + + @Override + public void parse(String content) throws Exception{ + parse(ListUtil.toList(content)); + } + + @Override + public void parse(List contentList) throws Exception { + if (CollectionUtil.isEmpty(contentList)) { + return; + } + + List jsonObjectList = ListUtil.toList(); + for (String content : contentList){ + JSONObject ruleObject = convertToJson(content); + jsonObjectList.add(ruleObject); + } + + super.parseJsonObject(jsonObjectList); + } + + protected JSONObject convertToJson(String yamlString) { + Yaml yaml= new Yaml(); + Map map = yaml.load(yamlString); + return JSON.parseObject(JSON.toJSONString(map)); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperJsonFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperJsonFlowELParser.java new file mode 100644 index 000000000..d2ada6a8a --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperJsonFlowELParser.java @@ -0,0 +1,64 @@ +package com.yomahub.liteflow.parser.el; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.exception.ParseException; +import com.yomahub.liteflow.parser.JsonFlowParser; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.NodeCache; +import org.apache.curator.retry.RetryNTimes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.List; + +/** + * 基于zk方式的json形式的解析器 + * @author guodongqing + * @since 2.5.0 + */ +public class ZookeeperJsonFlowELParser extends JsonFlowELParser { + + private static final Logger LOG = LoggerFactory.getLogger(ZookeeperJsonFlowELParser.class); + + private final String nodePath; + + public ZookeeperJsonFlowELParser(String node) { + nodePath = node; + } + + @Override + public void parseMain(List pathList) throws Exception { + //zk不允许有多个path + String path = pathList.get(0); + CuratorFramework client = CuratorFrameworkFactory.newClient( + path, + new RetryNTimes(10, 5000) + ); + client.start(); + + if (client.checkExists().forPath(nodePath) == null) { + client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes()); + } + + String content = new String(client.getData().forPath(nodePath)); + + + if (StrUtil.isBlank(content)) { + String error = MessageFormat.format("the node[{0}] value is empty", nodePath); + throw new ParseException(error); + } + parse(content); + + + final NodeCache cache = new NodeCache(client,nodePath); + cache.start(); + + cache.getListenable().addListener(() -> { + String content1 = new String(cache.getCurrentData().getData()); + LOG.info("stating load flow config...."); + parse(content1); + }); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperXmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperXmlFlowELParser.java new file mode 100644 index 000000000..f55979f2a --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperXmlFlowELParser.java @@ -0,0 +1,64 @@ +package com.yomahub.liteflow.parser.el; + +import cn.hutool.core.util.StrUtil; +import com.yomahub.liteflow.exception.ParseException; +import com.yomahub.liteflow.parser.XmlFlowParser; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.NodeCache; +import org.apache.curator.retry.RetryNTimes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.List; + +/** + * 基于zk方式的xml形式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public class ZookeeperXmlFlowELParser extends XmlFlowELParser { + + private static final Logger LOG = LoggerFactory.getLogger(ZookeeperXmlFlowELParser.class); + + private final String nodePath; + + public ZookeeperXmlFlowELParser(String node) { + nodePath = node; + } + + @Override + public void parseMain(List pathList) throws Exception { + //zk不允许有多个path + String path = pathList.get(0); + CuratorFramework client = CuratorFrameworkFactory.newClient( + path, + new RetryNTimes(10, 5000) + ); + client.start(); + + if (client.checkExists().forPath(nodePath) == null) { + client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes()); + } + + String content = new String(client.getData().forPath(nodePath)); + + + if (StrUtil.isBlank(content)) { + String error = MessageFormat.format("the node[{0}] value is empty", nodePath); + throw new ParseException(error); + } + parse(content); + + + final NodeCache cache = new NodeCache(client,nodePath); + cache.start(); + + cache.getListenable().addListener(() -> { + String content1 = new String(cache.getCurrentData().getData()); + LOG.info("stating load flow config...."); + parse(content1); + }); + } +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperYmlFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperYmlFlowELParser.java new file mode 100644 index 000000000..35930e29a --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/ZookeeperYmlFlowELParser.java @@ -0,0 +1,68 @@ +package com.yomahub.liteflow.parser.el; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.yomahub.liteflow.exception.ParseException; +import com.yomahub.liteflow.parser.YmlFlowParser; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.NodeCache; +import org.apache.curator.retry.RetryNTimes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.List; + +/** + * 基于zk方式的yml形式EL表达式解析器 + * @author Bryan.Zhang + * @since 2.8.0 + */ +public class ZookeeperYmlFlowELParser extends YmlFlowELParser { + + private static final Logger LOG = LoggerFactory.getLogger(ZookeeperYmlFlowELParser.class); + + private final String nodePath; + + public ZookeeperYmlFlowELParser(String node) { + nodePath = node; + } + + @Override + public void parseMain(List pathList) throws Exception { + //zk不允许有多个path + String path = pathList.get(0); + CuratorFramework client = CuratorFrameworkFactory.newClient( + path, + new RetryNTimes(10, 5000) + ); + client.start(); + + if (client.checkExists().forPath(nodePath) == null) { + client.create().creatingParentsIfNeeded().forPath(nodePath, "".getBytes()); + } + + String content = new String(client.getData().forPath(nodePath)); + + if (StrUtil.isBlank(content)) { + String error = MessageFormat.format("the node[{0}] value is empty", nodePath); + throw new ParseException(error); + } + + JSONObject ruleObject = convertToJson(content); + + parse(ruleObject.toJSONString()); + + + final NodeCache cache = new NodeCache(client,nodePath); + cache.start(); + + cache.getListenable().addListener(() -> { + String content1 = new String(cache.getCurrentData().getData()); + LOG.info("stating load flow config...."); + JSONObject ruleObject1 = convertToJson(content1); + parse(ruleObject1.toJSONString()); + }); + } +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java index 123f10fe8..e312aefb0 100644 --- a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/BaseELSpringbootTest.java @@ -15,9 +15,8 @@ import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; /** - * springboot环境最普通的例子测试 + * springboot环境EL常规的例子测试 * @author Bryan.Zhang - * @since 2.6.4 */ @RunWith(SpringRunner.class) @TestPropertySource(value = "classpath:/base/application.properties") @@ -29,10 +28,32 @@ public class BaseELSpringbootTest extends BaseTest { @Resource private FlowExecutor flowExecutor; + //最简单的情况 @Test - public void testBase() throws Exception{ + public void testBase1() throws Exception{ LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); Assert.assertTrue(response.isSuccess()); } + //switch节点最简单的测试用例 + @Test + public void testBase2() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //then,when,switch混用的稍微复杂点的用例,switch跳到一个then上 + @Test + public void testBase3() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg"); + Assert.assertTrue(response.isSuccess()); + } + + //一个非常复杂的例子,可以看base目录下的img.png这个图示 + @Test + public void testBase4() throws Exception{ + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg"); + Assert.assertTrue(response.isSuccess()); + } + } diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java index ab0317f69..bdf5ca9b3 100644 --- a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/DCmp.java @@ -15,7 +15,7 @@ public class DCmp extends NodeComponent { @Override public void process() { - System.out.println("CCmp executed!"); + System.out.println("DCmp executed!"); } } diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java new file mode 100644 index 000000000..fe912ad65 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ESwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.springframework.stereotype.Component; + +@Component("e") +public class ESwitchCmp extends NodeSwitchComponent { + + @Override + public String processCond() throws Exception { + return "d"; + } +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java new file mode 100644 index 000000000..823e0ad79 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/FCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("f") +public class FCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("FCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java new file mode 100644 index 000000000..5490e6865 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/GSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.springframework.stereotype.Component; + +@Component("g") +public class GSwitchCmp extends NodeSwitchComponent { + + @Override + public String processCond() throws Exception { + return "then_1001"; + } +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java new file mode 100644 index 000000000..e351d0df4 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/HCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("h") +public class HCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("HCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java new file mode 100644 index 000000000..bec1bb1e4 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ICmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("i") +public class ICmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ICmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java new file mode 100644 index 000000000..6db72bf80 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/JCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("j") +public class JCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("JCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java new file mode 100644 index 000000000..ea3f577d9 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/KCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("k") +public class KCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("KCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java new file mode 100644 index 000000000..7ca5015b9 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/MCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("m") +public class MCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("MCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java new file mode 100644 index 000000000..f6270d4ec --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/NCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("n") +public class NCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("NCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java new file mode 100644 index 000000000..a75a31a30 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/PCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("p") +public class PCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("PCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java new file mode 100644 index 000000000..e937c1e48 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/QCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("q") +public class QCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("QCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java new file mode 100644 index 000000000..d74c87f5b --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/RCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("r") +public class RCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("RCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java new file mode 100644 index 000000000..13c28c618 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/XSwitchCmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeSwitchComponent; +import org.springframework.stereotype.Component; + +@Component("x") +public class XSwitchCmp extends NodeSwitchComponent { + + @Override + public String processCond() throws Exception { + return "w01"; + } +} diff --git a/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java new file mode 100644 index 000000000..3c4801f1e --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/base/cmp/ZCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.base.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("z") +public class ZCmp extends NodeComponent { + + @Override + public void process() { + System.out.println("ZCmp executed!"); + } + +} diff --git a/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml b/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml index 7068d6cee..cd11ba12a 100644 --- a/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml +++ b/liteflow-testcase-el-springboot/src/test/resources/base/flow.el.xml @@ -1,7 +1,40 @@ - - + THEN(a,b,WHEN(c,d)) + + + + THEN( + a,b, + SWITCH(e).to(d,f) + ) + + + + THEN( + a, + WHEN( + c, + SWITCH(g).to(b, d, THEN(h,i).id("then_1001")) + ) + ) + + + + THEN( + a,b, + WHEN( + THEN(c, WHEN(j,k)), + d, + THEN(h, i) + ), + SWITCH(x).to( + m, + n, + WHEN(q, THEN(p, r)).id("w01") + ), + z + ) \ No newline at end of file diff --git a/liteflow-testcase-el-springboot/src/test/resources/base/img.png b/liteflow-testcase-el-springboot/src/test/resources/base/img.png new file mode 100644 index 000000000..b6dc946ac Binary files /dev/null and b/liteflow-testcase-el-springboot/src/test/resources/base/img.png differ diff --git a/liteflow-testcase-el-springboot/src/test/resources/logback.xml b/liteflow-testcase-el-springboot/src/test/resources/logback.xml new file mode 100644 index 000000000..330ece391 --- /dev/null +++ b/liteflow-testcase-el-springboot/src/test/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + + + + + + + +