美文网首页
Java中运行JavaScript代码(一)

Java中运行JavaScript代码(一)

作者: 不1见2不3散4 | 来源:发表于2018-12-23 11:57 被阅读0次

    项目需求:

    客户动态填写一些规则,根据规则生成告警提醒变化之类的信息,例如温度过高给出告警,设备属性变化给出提示等等。然而客户的判断这些变化的规则是不断改变的,因此需要动态输入。jvm支持多种动态语言,我们可以从java中调用JavaScript、Groovy、Ruby以及Scheme和Haskell编写的脚本,考虑到语言的流行程度,我们选择了js。

    实例代码:

    本代码主要来自《写给大忙人看的Jave SE 9核心技术》一书第14章,编译与脚本。

    首先,我们需要获取脚本执行引擎。脚本执行引擎就是以特定语言执行脚本的类库。jvm启动是,就会启动这些脚本引擎,我们可以通过new ScriptEngineManager()来获取脚本引擎管理器,然后通过getEngineByName(...)方法获取的对应的脚本引擎,我们使用的JavaScript语言,因此使用参数“nashorn”获取ScriptEngine。

    注意:There is no requirement for a given Java Virtual Machine (JVM) to include any engines by default, but the Oracle JVM (Java 6 and later) includes a JavaScript engine, based on Rhino version 1.6R2 before Java 8, and Nashorn since Java 8.

    Java 8 之前的jvm中JavaScript的ScriptEngine name Rhino, 之后的是Rashorn

    官方文档:
    https://jcp.org/aboutJava/communityprocess/final/jsr223/index.html Scripting for the JavaTM Platform

    package com.yq.js;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import lombok.experimental.var;
    import lombok.extern.slf4j.Slf4j;
    import lombok.extern.java.Log;
    
    import javax.script.Bindings;
    import javax.script.Invocable;
    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;
    import javax.script.ScriptException;
    import java.io.File;
    import java.io.Reader;
    import java.io.StringWriter;
    import java.nio.charset.Charset;
    import java.nio.file.Files;
    import java.nio.file.Path;
    
    
    /**
     * Simple to Introduction
     * className: JavaJSDemo
     *
     * @author EricYang
     * @version 2018/12/22 9:51
     */
    
    @Slf4j
    public class JavaJSDemo {
    
        private static final String JS_ENGINE_NAME= "nashorn";
        private final ScriptEngineManager sem = new ScriptEngineManager();
        private final ScriptEngine engine = sem.getEngineByName(JS_ENGINE_NAME);
    
        public static void main(String[] args) {
            JavaJSDemo demo = new JavaJSDemo();
    
            demo.bindingDemo();
            demo.reDirectIODemo();
            demo.invokeFunctionDemo();
            demo.invokeFunctionByFileDemo();
        }
    
        public void bindingDemo() {
            try {
                engine.put("msg", "hello world!");
                Object result = engine.eval("msg");
                log.info("result=" + result);
    
                engine.put("k", 20);
                result = engine.eval("k + 1");
                log.info("result=" + result);
    
    
                result = engine.eval("n = 1738");
                log.info("result=" + result);
                result = engine.get("n");
                log.info("result=" + result);
    
                Bindings scope = engine.createBindings();
                scope.put("key", "西安");
                result = engine.eval("key + '市'", scope);
                log.info("result=" + result);
            }
            catch (ScriptException se) {
               log.warn("binding demo exception.", se);
            }
        }
    
        public void reDirectIODemo() {
            log.info("---          redirect IO          ---" );
            try {
                StringWriter writer = new StringWriter();
                engine.getContext().setWriter(writer);
                engine.put("msg", "hello world!");
                //任何一print函数输出的内容都会送到writer对象中
                Object result = engine.eval("print(msg)");
                log.info("result=" + result);
                log.info("result=" + writer.toString());
    
                //js中直接调用java的System.out.println
                 result = engine.eval("java.lang.System.out.println(msg)");
                log.info("result=" + result);
                log.info("result=" + writer.toString());
    
            }
            catch (ScriptException se) {
                log.warn("binding demo exception.", se);
            }
        }
    
        public boolean invokeFunctionDemo() {
            log.info("---          invokeFunction         ---" );
            boolean result = true;
            try {
                engine.put("msg", "hello world!");
                String str = "var user = {name:'张三',age:18,city:['陕西','台湾']};";
                engine.eval(str);
    
                log.info("Get msg={}", engine.get("msg"));
                //获取变量
                engine.eval("var sum = eval('1 + 2 + 3*4');");
                //调用js的eval的方法完成运算
                log.info("get sum={}", engine.get("sum"));
    
                JSONObject msg = new JSONObject();
                msg.put("temperature", 125);
                msg.put("humidity", 20);
                msg.put("voltage", 220);
                msg.put("electricity", 13);
    
                JSONObject metadata = new JSONObject();
                metadata.put("deviceName", "空气质量检测器01");
                metadata.put("contacts", "张三");
    
                JSONObject msgType = new JSONObject();
                //msgType.put("type", "deviceTelemetryData");
                msgType.put("type", "deviceTelemetryData1");
    
                //定义函数
                String func = "var result = true; \r\n" +
                        "if (msgType.type = 'deviceTelemetryData') { \r\n" +
                        "   if (msg.temperature >0 && msg.temperature < 33) { \n       result = true ;}  \n" +
                        "   else { \n       result = false;}  \n" +
                        "} else { \n     result = false;  \n" +
                        "     var errorMsg = msgType.type + ' is not deviceTelemetryData';  \n" +
                        "     print(msgType.type) \n } \n\n" +
                        "return result";
                log.info("func = {}", func);
                engine.eval("function filter(msg, metadata, msgType){ " + func + "}");
                // 执行js函数
                Invocable jsInvoke = (Invocable) engine;
                Object obj = jsInvoke.invokeFunction("filter", msg, metadata, msgType);
                //方法的名字,参数
                log.info("function result={}", obj);
                result = (Boolean)obj;
            }
            catch(Exception ex) {
                log.warn("exception", ex);
                result = false;
            }
    
            return result;
        }
    
        public int invokeFunctionByFileDemo() {
            log.info("---          invokeFunction         ---" );
            int result = 0;
            try {
                log.info("Current dir={}", System.getProperty("user.dir"));
                //\AkkaDemo\src\main\resources\demo.js
                File file = new File("./AkkaDemo/src/main/resources/demo.js");
                Reader reader = Files.newBufferedReader(file.toPath(), Charset.defaultCharset());
    
                engine.put("user", "{name:'张三',age:18,city:['陕西','台湾']};");
                Object obj = engine.eval(reader);
    
                log.info("get age={}", engine.get("age"));
    
                log.info("function result={}", obj);
                
                URL resource = this.getClass().getClassLoader().getResource("demo2.js");
                FileReader fileReader = new FileReader(resource.getPath());
                engine.eval(fileReader);
                //执行js函数
                Invocable jsInvoke = (Invocable)engine;
                obj = jsInvoke.invokeFunction("myAdd", 1, 2);
                log.info("myAdd obj={}", obj);
            }
            catch(Exception ex) {
                log.warn("exception", ex);
            }
    
            return result;
        }
    }
    
    

    说明:
    1,demo.js 内容为 var age = 20;
    2,demo2.js 内容为
    function myAdd(a,b){
    var sum = a + b;
    return sum;
    }

    运行效果:

    11:34:26.170 [main] INFO  com.yq.js.JavaJSDemo - result=hello world!
    11:34:26.186 [main] INFO  com.yq.js.JavaJSDemo - result=21.0
    11:34:26.195 [main] INFO  com.yq.js.JavaJSDemo - result=1738
    11:34:26.195 [main] INFO  com.yq.js.JavaJSDemo - result=1738
    11:34:26.205 [main] INFO  com.yq.js.JavaJSDemo - result=西安市
    11:34:26.205 [main] INFO  com.yq.js.JavaJSDemo - ---          redirect IO          ---
    11:34:26.212 [main] INFO  com.yq.js.JavaJSDemo - result=null
    11:34:26.213 [main] INFO  com.yq.js.JavaJSDemo - result=hello world!
    
    hello world!
    11:34:26.253 [main] INFO  com.yq.js.JavaJSDemo - result=null
    11:34:26.253 [main] INFO  com.yq.js.JavaJSDemo - result=hello world!
    
    11:34:26.253 [main] INFO  com.yq.js.JavaJSDemo - ---          invokeFunction         ---
    11:34:26.261 [main] INFO  com.yq.js.JavaJSDemo - Get msg=hello world!
    11:34:26.272 [main] INFO  com.yq.js.JavaJSDemo - get sum=15
    11:34:26.280 [main] INFO  com.yq.js.JavaJSDemo - func = var result = true; 
    if (msgType.type = 'deviceTelemetryData') { 
       if (msg.temperature >0 && msg.temperature < 33) { 
           result = true ;}  
       else { 
           result = false;}  
    } else { 
         result = false;  
         var errorMsg = msgType.type + ' is not deviceTelemetryData';  
         print(msgType.type) 
     } 
    
    return result
    11:34:26.317 [main] INFO  com.yq.js.JavaJSDemo - function result=false
    11:34:26.317 [main] INFO  com.yq.js.JavaJSDemo - ---          invokeFunction         ---
    11:34:26.317 [main] INFO  com.yq.js.JavaJSDemo - Current dir=D:\E\workspaceGitub\springboot
    11:34:26.328 [main] INFO  com.yq.js.JavaJSDemo - get age=20
    11:34:26.328 [main] INFO  com.yq.js.JavaJSDemo - function result=null
    11:34:26.334 [main] INFO  com.yq.js.JavaJSDemo - myAdd obj=3.0
    
    Process finished with exit code 0
    
    

    相关文章

      网友评论

          本文标题:Java中运行JavaScript代码(一)

          本文链接:https://www.haomeiwen.com/subject/mdzgkqtx.html