diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java index 3b0b4ad0e..e948909e0 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/NodeComponent.java @@ -476,14 +476,23 @@ public abstract class NodeComponent{ } } - public List getBindDataList(Class clazz) { - String bindData = getRefNode().getCmpData(); + public List getBindDataList(String key, Class clazz) { + String bindData = getRefNode().getBindData(key); if (StrUtil.isBlank(bindData)) { return null; } return JsonUtil.parseList(bindData, clazz); } + @SuppressWarnings("unchecked") + public T getContextValue(String expression){ + return (T)LiteflowContextRegexMatcher.searchContext(this.getSlot().getContextBeanList(), expression); + } + + public void setContextValue(String methodExpress, Object... values){ + LiteflowContextRegexMatcher.searchAndSetContext(this.getSlot().getContextBeanList(), methodExpress, values); + } + public Integer getLoopIndex() { return this.getRefNode().getLoopIndex(); } @@ -539,9 +548,4 @@ public abstract class NodeComponent{ return originalClass.getName(); } - public static void main(String[] args) { - - boolean flag = ReUtil.isMatch(ChainConstant.CONTEXT_SEARCH_REGEX, "${user.name}"); - System.out.println(ReUtil.getGroup1(ChainConstant.CONTEXT_SEARCH_REGEX, "${user.name}")); - } } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java index 61b8e83db..a626caecd 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/util/LiteflowContextRegexMatcher.java @@ -1,14 +1,22 @@ package com.yomahub.liteflow.util; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Tuple; +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; import com.ql.util.express.DefaultContext; import com.ql.util.express.ExpressRunner; import com.ql.util.express.InstructionSet; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntFunction; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * LiteFlow上下文正则表达式匹配器 @@ -54,4 +62,47 @@ public class LiteflowContextRegexMatcher { return result; } + + public static void searchAndSetContext(List contextList, String methodExpress, Object... args){ + // 把上下文数据转换成map形式的,key为别名,value为上下文 + Map contextMap = contextList.stream().collect( + Collectors.toMap(tuple -> tuple.get(0), tuple -> tuple.get(1)) + ); + + List errorList = new ArrayList<>(); + + boolean flag = false; + + String argStr = IntStream.range(0, args.length).mapToObj( + idx -> StrUtil.format("arg{}", idx) + ).collect(Collectors.joining(",")); + + List> tupleList = IntStream.range(0, args.length).mapToObj( + idx -> new TupleOf2<>(StrUtil.format("arg{}", idx), idx) + ).collect(Collectors.toList()); + + for(Map.Entry entry : contextMap.entrySet()){ + try{ + InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(StrUtil.format("{}.{}({})", entry.getKey(), methodExpress, argStr)); + DefaultContext context = new DefaultContext<>(); + context.put(entry.getKey(), entry.getValue()); + tupleList.forEach(tuple -> context.put(tuple.getA(), args[tuple.getB()])); + expressRunner.execute(instructionSet, context, errorList, false, false); + flag = true; + break; + }catch (Exception ignore){} + } + + // 根据表达式去上下文里搜索相匹配的数据 + if (BooleanUtil.isFalse(flag)){ + try{ + // 如果没有搜到,那么尝试推断表达式是指定的上下文,按照指定上下文的方式去再获取 + InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(StrUtil.format("contextMap.{}({})", methodExpress, argStr)); + DefaultContext context = new DefaultContext<>(); + context.put("contextMap", contextMap); + tupleList.forEach(tuple -> context.put(tuple.getA(), args[tuple.getB()])); + expressRunner.execute(instructionSet, context, errorList, false, false); + }catch (Exception ignore){} + } + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/SearchContextSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/SearchContextSpringbootTest.java new file mode 100644 index 000000000..ad84cb12d --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/SearchContextSpringbootTest.java @@ -0,0 +1,100 @@ +package com.yomahub.liteflow.test.searchContext; + +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import com.yomahub.liteflow.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import com.yomahub.liteflow.test.searchContext.context.Member; +import com.yomahub.liteflow.test.searchContext.context.MemberContext; +import com.yomahub.liteflow.test.searchContext.context.OrderContext; +import com.yomahub.liteflow.test.searchContext.context.UserInfoContext; +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.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; + +import javax.annotation.Resource; + +/** + * springboot环境EL常规的例子测试 + * + * @author Bryan.Zhang + */ +@TestPropertySource(value = "classpath:/searchContext/application.properties") +@SpringBootTest(classes = SearchContextSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.searchContext.cmp"}) +public class SearchContextSpringbootTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + // 测试动态取,动态设置的基础情况 + @Test + public void testSearchContext1() throws Exception { + MemberContext memberContext = new MemberContext(); + memberContext.setId(31); + memberContext.setName("jack"); + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", memberContext, new DefaultContext()); + Assertions.assertTrue(response.isSuccess()); + MemberContext context = response.getContextBean(MemberContext.class); + Assertions.assertEquals("hello,jack", context.getName()); + } + + // 测试动态取,2个上下文智能设置,1个参数 + @Test + public void testSearchContext2() throws Exception { + MemberContext memberContext = new MemberContext(); + memberContext.setId(31); + memberContext.setName("jack"); + LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg", memberContext, new DefaultContext()); + Assertions.assertTrue(response.isSuccess()); + MemberContext context = response.getContextBean(MemberContext.class); + Assertions.assertEquals("hello,jack", context.getName()); + } + + // 多级动态取,2个上下文智能设置,多个参数 + @Test + public void testSearchContext3() throws Exception { + OrderContext orderContext = new OrderContext(); + orderContext.setOrderCode("SO1234"); + orderContext.setMember(new Member("M0001","jack")); + LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg", orderContext, new DefaultContext()); + Assertions.assertTrue(response.isSuccess()); + DefaultContext context = response.getContextBean(DefaultContext.class); + Assertions.assertEquals("M0001", context.getData("test")); + } + + // 3个上下文指定上下文取和设置 + @Test + public void testSearchContext4() throws Exception { + MemberContext memberContext = new MemberContext(); + memberContext.setId(2000); + memberContext.setName("jack"); + + OrderContext orderContext = new OrderContext(); + orderContext.setId(3000); + orderContext.setOrderCode("SO1234"); + orderContext.setMember(new Member("M0001","jack")); + + LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg", memberContext, orderContext, new DefaultContext()); + Assertions.assertTrue(response.isSuccess()); + DefaultContext context = response.getContextBean(DefaultContext.class); + Assertions.assertEquals(3000, (Integer) context.getData("test")); + } + + // 多个上下文,结合@ContextBean测试 + @Test + public void testSearchContext5() throws Exception { + UserInfoContext userInfoContext = new UserInfoContext(); + userInfoContext.setInfo("test info"); + + LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg", userInfoContext, new DefaultContext()); + Assertions.assertTrue(response.isSuccess()); + DefaultContext context = response.getContextBean(DefaultContext.class); + Assertions.assertEquals("test info", context.getData("test")); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A1Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A1Cmp.java new file mode 100644 index 000000000..4a88c7259 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A1Cmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.searchContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a1") +public class A1Cmp extends NodeComponent { + + @Override + public void process() { + String name = this.getContextValue("name"); + + this.setContextValue("setName", "hello," + name); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A2Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A2Cmp.java new file mode 100644 index 000000000..9989b15d9 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A2Cmp.java @@ -0,0 +1,23 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.searchContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a2") +public class A2Cmp extends NodeComponent { + + @Override + public void process() { + String name = this.getContextValue("name"); + + this.setContextValue("memberContext.setName", "hello," + name); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A3Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A3Cmp.java new file mode 100644 index 000000000..585b2cfb8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A3Cmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.searchContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a3") +public class A3Cmp extends NodeComponent { + + @Override + public void process() { + String name = this.getContextValue("member.memberCode"); + this.setContextValue("setData", "test", name); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A4Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A4Cmp.java new file mode 100644 index 000000000..e36958ec1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A4Cmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.searchContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a4") +public class A4Cmp extends NodeComponent { + + @Override + public void process() { + Integer id = this.getContextValue("orderContext.id"); + this.setContextValue("setData", "test", id); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A5Cmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A5Cmp.java new file mode 100644 index 000000000..67379dc59 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/cmp/A5Cmp.java @@ -0,0 +1,22 @@ +/** + *

Title: liteflow

+ *

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

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.searchContext.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +@Component("a5") +public class A5Cmp extends NodeComponent { + + @Override + public void process() { + String str = this.getContextValue("userCx.info"); + this.setContextValue("setData", "test", str); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/Member.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/Member.java new file mode 100644 index 000000000..d4d3d7297 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/Member.java @@ -0,0 +1,28 @@ +package com.yomahub.liteflow.test.searchContext.context; + +public class Member { + private String memberCode; + + private String memberName; + + public Member(String memberCode, String memberName) { + this.memberCode = memberCode; + this.memberName = memberName; + } + + public String getMemberCode() { + return memberCode; + } + + public void setMemberCode(String memberCode) { + this.memberCode = memberCode; + } + + public String getMemberName() { + return memberName; + } + + public void setMemberName(String memberName) { + this.memberName = memberName; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/MemberContext.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/MemberContext.java new file mode 100644 index 000000000..ec05f8702 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/MemberContext.java @@ -0,0 +1,24 @@ +package com.yomahub.liteflow.test.searchContext.context; + +public class MemberContext { + + private Integer id; + + private String name; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/OrderContext.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/OrderContext.java new file mode 100644 index 000000000..09adf86c0 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/OrderContext.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.test.searchContext.context; + +public class OrderContext { + + private Integer id; + + private String orderCode; + + private Member member; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getOrderCode() { + return orderCode; + } + + public void setOrderCode(String orderCode) { + this.orderCode = orderCode; + } + + public Member getMember() { + return member; + } + + public void setMember(Member member) { + this.member = member; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/UserInfoContext.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/UserInfoContext.java new file mode 100644 index 000000000..f6b4ee56e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/searchContext/context/UserInfoContext.java @@ -0,0 +1,17 @@ +package com.yomahub.liteflow.test.searchContext.context; + +import com.yomahub.liteflow.context.ContextBean; + +@ContextBean("userCx") +public class UserInfoContext { + + private String info; + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/application.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/application.properties new file mode 100644 index 000000000..8f2ef4e5e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/application.properties @@ -0,0 +1 @@ +liteflow.rule-source=searchContext/flow.xml \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/flow.xml new file mode 100644 index 000000000..8ff81a09c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/searchContext/flow.xml @@ -0,0 +1,23 @@ + + + + + THEN(a1); + + + + THEN(a2); + + + + THEN(a3); + + + + THEN(a4); + + + + THEN(a5); + + \ No newline at end of file