Java中运行js代码

项目需求:

客户动态填写一些规则,根据规则生成告警提醒变化之类的信息,例如温度过高给出告警,设备属性变化给出提示等等。然而客户的判断这些变化的规则是不断改变的,因此需要动态输入。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, 之后的是nashorn

官方文档:
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= "JavaScript";
    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

本文转自:russle
https://blog.csdn.net/russle/article/details/85214044?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-2.channel_param

  • 0
    点赞
  • 3
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

java小白-说

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值