Javaでjavascriptコードを実行する(一)

41538 ワード

プロジェクト要件:
お客様は、温度が高すぎると警告されたり、デバイスのプロパティが変化したりするなど、ルールに基づいて警告注意の変化などの情報を生成するルールを動的に記入します.しかし、お客様の判断は、これらの変化のルールが絶えず変化しているため、動的な入力が必要です.jvmは複数の動的言語をサポートしており、javaからJavaScript、Groovy、Ruby、Scheme、Haskellが作成したスクリプトを呼び出すことができ、言語の流行度を考慮してjsを選択しました.
インスタンスコード:
このコードは主に『大忙しの人に読むJave SE 9コアテクノロジー』第14章から来ており、コンパイルとスクリプトです.
まず、スクリプト実行エンジンを取得する必要があります.スクリプト実行エンジンは、特定の言語でスクリプトを実行するクラスライブラリです.jvm起動はい、これらのスクリプトエンジンが起動します.new Script EngineManager()でスクリプトエンジンマネージャを取得し、getEngineByName(...)メソッドで取得した対応するスクリプトエンジン、JavaScript言語を使用するため、パラメータ「nashorn」を使用してScript Engineを取得します.
注意: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.6 R 2 before Java 8,and Nashorn since Java 8.
Java 8より前のjvmでJavaScriptのScript Engine 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= "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
"
+ "if (msgType.type = 'deviceTelemetryData') { \r
"
+ " 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"; 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,demo 2.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