diff --git a/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java b/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java
index c415d13e3..23064ddf7 100644
--- a/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java
+++ b/liteflow-script-plugin/liteflow-script-groovy/src/main/java/com/yomahub/liteflow/script/groovy/GroovyScriptExecutor.java
@@ -16,7 +16,6 @@ import org.slf4j.LoggerFactory;
import javax.script.*;
import java.util.Map;
-import java.util.function.Consumer;
/**
* Groovy脚本语言的执行器实现
diff --git a/liteflow-script-plugin/liteflow-script-javascript/pom.xml b/liteflow-script-plugin/liteflow-script-javascript/pom.xml
new file mode 100644
index 000000000..2796eeefc
--- /dev/null
+++ b/liteflow-script-plugin/liteflow-script-javascript/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ liteflow-script-plugin
+ com.yomahub
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ liteflow-script-javascript
+
+
+
+ com.yomahub
+ liteflow-core
+ ${revision}
+ provided
+
+
+
\ No newline at end of file
diff --git a/liteflow-script-plugin/liteflow-script-javascript/src/main/java/com/yomahub/liteflow/script/javascript/JavaScriptExecutor.java b/liteflow-script-plugin/liteflow-script-javascript/src/main/java/com/yomahub/liteflow/script/javascript/JavaScriptExecutor.java
new file mode 100644
index 000000000..a5888eecd
--- /dev/null
+++ b/liteflow-script-plugin/liteflow-script-javascript/src/main/java/com/yomahub/liteflow/script/javascript/JavaScriptExecutor.java
@@ -0,0 +1,103 @@
+package com.yomahub.liteflow.script.javascript;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.script.ScriptBeanManager;
+import com.yomahub.liteflow.script.ScriptExecuteWrap;
+import com.yomahub.liteflow.slot.DataBus;
+import com.yomahub.liteflow.slot.Slot;
+import com.yomahub.liteflow.script.ScriptExecutor;
+import com.yomahub.liteflow.script.exception.ScriptExecuteException;
+import com.yomahub.liteflow.script.exception.ScriptLoadException;
+import com.yomahub.liteflow.util.CopyOnWriteHashMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.*;
+import java.util.Map;
+
+/**
+ * JavaScript脚本语言的执行器实现
+ * @author Bryan.Zhang
+ * @since 2.9.1
+ */
+public class JavaScriptExecutor implements ScriptExecutor {
+
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ private ScriptEngine scriptEngine;
+
+ private final Map compiledScriptMap = new CopyOnWriteHashMap<>();
+
+ @Override
+ public ScriptExecutor init() {
+ ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+ scriptEngine = scriptEngineManager.getEngineByName("javascript");
+ return this;
+ }
+
+ @Override
+ public void load(String nodeId, String script) {
+ try{
+ CompiledScript compiledScript = ((Compilable) scriptEngine).compile(script);
+ compiledScriptMap.put(nodeId, compiledScript);
+ }catch (Exception e){
+ String errorMsg = StrUtil.format("script loading error for node[{}], error msg:{}", nodeId, e.getMessage());
+ throw new ScriptLoadException(errorMsg);
+ }
+
+ }
+
+ @Override
+ public Object execute(ScriptExecuteWrap wrap) {
+ try{
+ if (!compiledScriptMap.containsKey(wrap.getNodeId())){
+ String errorMsg = StrUtil.format("script for node[{}] is not loaded", wrap.getNodeId());
+ throw new ScriptLoadException(errorMsg);
+ }
+
+ CompiledScript compiledScript = compiledScriptMap.get(wrap.getNodeId());
+ Bindings bindings = new SimpleBindings();
+
+ //往脚本语言绑定表里循环增加绑定上下文的key
+ //key的规则为自定义上下文的simpleName
+ //比如你的自定义上下文为AbcContext,那么key就为:abcContext
+ //这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
+ DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
+ String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
+ bindings.put(key, o);
+ });
+
+ //把wrap对象转换成元数据map
+ Map metaMap = BeanUtil.beanToMap(wrap);
+
+ //在元数据里放入主Chain的流程参数
+ Slot slot = DataBus.getSlot(wrap.getSlotIndex());
+ metaMap.put("requestData", slot.getRequestData());
+
+ //如果有隐式流程,则放入隐式流程的流程参数
+ Object subRequestData = slot.getChainReqData(wrap.getCurrChainName());
+ if (ObjectUtil.isNotNull(subRequestData)){
+ metaMap.put("subRequestData", subRequestData);
+ }
+
+ //往脚本上下文里放入元数据
+ bindings.put("_meta", metaMap);
+
+ //放入用户自己定义的bean
+ bindings.putAll(ScriptBeanManager.getScriptBeanMap());
+
+ return compiledScript.eval(bindings);
+ }catch (Exception e){
+ log.error(e.getMessage(), e);
+ String errorMsg = StrUtil.format("script execute error for node[{}]", wrap.getNodeId());
+ throw new ScriptExecuteException(errorMsg);
+ }
+ }
+
+ @Override
+ public void cleanCache() {
+ compiledScriptMap.clear();
+ }
+}
diff --git a/liteflow-script-plugin/liteflow-script-javascript/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor b/liteflow-script-plugin/liteflow-script-javascript/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor
new file mode 100644
index 000000000..c331aee2e
--- /dev/null
+++ b/liteflow-script-plugin/liteflow-script-javascript/src/main/resources/META-INF/services/com.yomahub.liteflow.script.ScriptExecutor
@@ -0,0 +1,2 @@
+# JavaScript的实现
+com.yomahub.liteflow.script.javascript.JavaScriptExecutor
\ No newline at end of file
diff --git a/liteflow-script-plugin/pom.xml b/liteflow-script-plugin/pom.xml
index be8c8929b..7ca6966e9 100644
--- a/liteflow-script-plugin/pom.xml
+++ b/liteflow-script-plugin/pom.xml
@@ -17,6 +17,7 @@
liteflow-script-qlexpress
liteflow-script-groovy
+ liteflow-script-javascript
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/pom.xml b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/pom.xml
new file mode 100644
index 000000000..3bbe2ccae
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ liteflow-testcase-el
+ com.yomahub
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ liteflow-testcase-el-script-javascript-springboot
+
+
+
+ com.yomahub
+ liteflow-spring-boot-starter
+ ${revision}
+
+
+ com.yomahub
+ liteflow-script-javascript
+ ${revision}
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java
new file mode 100644
index 000000000..64886670f
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/BaseTest.java
@@ -0,0 +1,20 @@
+package com.yomahub.liteflow.test;
+
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.property.LiteflowConfigGetter;
+import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner;
+import com.yomahub.liteflow.spring.ComponentScanner;
+import com.yomahub.liteflow.thread.ExecutorHelper;
+import org.junit.AfterClass;
+
+public class BaseTest {
+
+ @AfterClass
+ public static void cleanScanCache(){
+ ComponentScanner.cleanCache();
+ FlowBus.cleanCache();
+ ExecutorHelper.loadInstance().clearExecutorServiceMap();
+ SpiFactoryCleaner.clean();
+ LiteflowConfigGetter.clean();
+ }
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/LiteflowXmlScriptJsELTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/LiteflowXmlScriptJsELTest.java
new file mode 100644
index 000000000..792e4d93e
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/LiteflowXmlScriptJsELTest.java
@@ -0,0 +1,45 @@
+package com.yomahub.liteflow.test.script.javascript.common;
+
+import cn.hutool.core.io.resource.ResourceUtil;
+import com.yomahub.liteflow.core.FlowExecutor;
+import com.yomahub.liteflow.enums.FlowParserTypeEnum;
+import com.yomahub.liteflow.flow.FlowBus;
+import com.yomahub.liteflow.flow.LiteflowResponse;
+import com.yomahub.liteflow.slot.DefaultContext;
+import com.yomahub.liteflow.test.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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 org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+
+
+/**
+ * 测试springboot下的groovy脚本组件,基于xml配置
+ * @author Bryan.Zhang
+ * @since 2.6.0
+ */
+@RunWith(SpringRunner.class)
+@TestPropertySource(value = "classpath:/common/application.properties")
+@SpringBootTest(classes = LiteflowXmlScriptJsELTest.class)
+@EnableAutoConfiguration
+@ComponentScan({"com.yomahub.liteflow.test.script.javascript.common.cmp"})
+public class LiteflowXmlScriptJsELTest extends BaseTest {
+
+ @Resource
+ private FlowExecutor flowExecutor;
+
+ //测试普通脚本节点
+ @Test
+ public void testCommon1() {
+ LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
+ DefaultContext context = response.getFirstContextBean();
+ Assert.assertTrue(response.isSuccess());
+ Assert.assertEquals(Double.valueOf(11), context.getData("s1"));
+ }
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/ACmp.java
new file mode 100644
index 000000000..c746d2bca
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/ACmp.java
@@ -0,0 +1,20 @@
+/**
+ * Title: liteflow
+ * Description: 轻量级的组件式流程框架
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javascript.common.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("a")
+public class ACmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("ACmp executed!");
+ }
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/BCmp.java
new file mode 100644
index 000000000..67196ecce
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/BCmp.java
@@ -0,0 +1,21 @@
+/**
+ * Title: liteflow
+ * Description: 轻量级的组件式流程框架
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javascript.common.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("b")
+public class BCmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("BCmp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/CCmp.java
new file mode 100644
index 000000000..ca9a0da81
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/CCmp.java
@@ -0,0 +1,21 @@
+/**
+ * Title: liteflow
+ * Description: 轻量级的组件式流程框架
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javascript.common.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+
+@LiteflowComponent("c")
+public class CCmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ System.out.println("CCmp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/DCmp.java
new file mode 100644
index 000000000..05541c698
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/java/com/yomahub/liteflow/test/script/javascript/common/cmp/DCmp.java
@@ -0,0 +1,24 @@
+/**
+ * Title: liteflow
+ * Description: 轻量级的组件式流程框架
+ * @author Bryan.Zhang
+ * @email weenyc31@163.com
+ * @Date 2020/4/1
+ */
+package com.yomahub.liteflow.test.script.javascript.common.cmp;
+
+import com.yomahub.liteflow.annotation.LiteflowComponent;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.yomahub.liteflow.slot.DefaultContext;
+
+@LiteflowComponent("d")
+public class DCmp extends NodeComponent {
+
+ @Override
+ public void process() {
+ DefaultContext context = this.getFirstContextBean();
+ context.setData("count",198);
+ System.out.println("DCmp executed!");
+ }
+
+}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/application.properties b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/application.properties
new file mode 100644
index 000000000..4c9c216b6
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/application.properties
@@ -0,0 +1 @@
+liteflow.rule-source=common/flow.xml
\ No newline at end of file
diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/flow.xml b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/flow.xml
new file mode 100644
index 000000000..8583b8558
--- /dev/null
+++ b/liteflow-testcase-el/liteflow-testcase-el-script-javascript-springboot/src/test/resources/common/flow.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+ THEN(a, b, c, s1);
+
+
\ No newline at end of file
diff --git a/liteflow-testcase-el/pom.xml b/liteflow-testcase-el/pom.xml
index f4e4388ca..690b7fbb8 100644
--- a/liteflow-testcase-el/pom.xml
+++ b/liteflow-testcase-el/pom.xml
@@ -22,6 +22,7 @@
liteflow-testcase-el-declare-multi-springboot
liteflow-testcase-el-script-groovy-springboot
liteflow-testcase-el-script-qlexpress-springboot
+ liteflow-testcase-el-script-javascript-springboot
liteflow-testcase-el-zk-springboot
liteflow-testcase-el-sql-springboot
liteflow-testcase-el-nacos-springboot
diff --git a/pom.xml b/pom.xml
index 249f23d9f..4cef7d4e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -340,7 +340,7 @@
liteflow-spring-boot-starter
liteflow-spring
liteflow-testcase-el
-
+