欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中如何調(diào)用js

 更新時(shí)間:2025年01月23日 11:08:08   作者:java_monkey_110  
Nashorn是Java8中引入的一個(gè)新的JavaScript引擎,它允許在JVM上運(yùn)行JavaScript代碼,并且可以與Java代碼相互調(diào)用,Nashorn遵循JSR233規(guī)范,是一個(gè)純Java實(shí)現(xiàn)的JavaScript引擎,可以與Java程序無縫集成,提供動(dòng)態(tài)腳本執(zhí)行和靈活性

java中調(diào)用js

我們都知道腳本語言非常靈活,在處理某些問題的時(shí)候 Java 實(shí)現(xiàn)用十幾行來寫,用 js 可能不到十行就寫完,并且非常簡(jiǎn)潔,那么有沒有一種優(yōu)雅的方式將 Java 與腳本語言結(jié)合呢,在 Java SE6(代號(hào) Mustang)中,這將成為現(xiàn)實(shí)。

Nashorn,一個(gè)新的 JavaScript 引擎隨著 Java 8 一起公諸于世,它允許在 JVM 上開發(fā)運(yùn)行某些 JavaScript 應(yīng)用。Nashorn 就是 javax.script.ScriptEngine 的另一種實(shí)現(xiàn),并且它們倆遵循相同的規(guī)則,允許 Java 與 JavaScript 相互調(diào)用。

Mustang 的腳本引擎

JSR 233 為 Java 設(shè)計(jì)了一套腳本語言 API。這一套 API 提供了在 Java 程序中調(diào)用各種腳本語言引擎的接口。

任何實(shí)現(xiàn)了這一接口的腳本語言引擎都可以在 Java 程序中被調(diào)用。在 Mustang 的發(fā)行版本中包括了一個(gè)基于 Mozilla Rhino 的 JavaScript 腳本引擎,也就是說在 JavaSE6+ 的版本默認(rèn)可以直接調(diào)用執(zhí)行 JavaScript。

Mozilla Rhino

Rhino 是一個(gè)純 Java 的開源的 JavaScript 實(shí)現(xiàn)。他的名字來源于 O’Reilly 關(guān)于 JavaScript 的書的封面,是的,就是那本犀牛書…

Rhino 項(xiàng)目可以追朔到 1997 年,當(dāng)時(shí) Netscape 計(jì)劃開發(fā)一個(gè)純 Java 實(shí)現(xiàn)的 Navigator,為此需要一個(gè) Java 實(shí)現(xiàn)的 JavaScript —— Javagator。

它也就是 Rhino 的前身。起初 Rhino 將 JavaScript 編譯成 Java 的二進(jìn)制代碼執(zhí)行,這樣它會(huì)有最好的性能。后來由于編譯執(zhí)行的方式存在垃圾收集的問題并且編譯和裝載過程的開銷過大,不能滿足一些項(xiàng)目的需求,Rhino 提供了解釋執(zhí)行的方式。

隨著 Rhino 開放源代碼,越來越多的用戶在自己的產(chǎn)品中使用了 Rhino,同時(shí)也有越來越多的開發(fā)者參與了 Rhino 的開發(fā)并做出了很大的貢獻(xiàn)。如今 Rhino 將被包含在 Java SE 中發(fā)行,更多的 Java 開發(fā)者將從中獲益。

Rhino 提供了如下功能:

  • 對(duì) JavaScript 1.5+ 的完全支持
  • 直接在 Java 中使用 JavaScript 的功能
  • 一個(gè) JavaScript shell 用于運(yùn)行 JavaScript 腳本
  • 一個(gè) JavaScript 的編譯器,用于將 JavaScript 編譯成 Java 二進(jìn)制文件

支持的腳本語言

在 dev.java.net 可以找到官方的腳本引擎的實(shí)現(xiàn)項(xiàng)目。這一項(xiàng)目基于BSD License ,表示這些腳本引擎的使用將十分自由。

目前該項(xiàng)目已對(duì)包括 Groovy, JavaScript, Python, Ruby, PHP 在內(nèi)的二十多種腳本語言提供了支持。這一支持列表還將不斷擴(kuò)大。

在Java中的基本使用

在 Mustang 中對(duì)腳本引擎的檢索使用了工廠模式。

首先需要實(shí)例化一個(gè)工廠 : ScriptEngineManager

ScriptEngineManager factory = new ScriptEngineManager();

ScriptEngineManager 將在 Thread Context ClassLoader 的 Classpath 中根據(jù) jar 文件的 META-INF 來查找可用的腳本引擎。

它提供了 3 種方法來檢索腳本引擎:

// create engine by name
ScriptEngine engine = factory.getEngineByName ("JavaScript");
// create engine by name
ScriptEngine engine = factory.getEngineByExtension ("js");
// create engine by name
ScriptEngine engine = factory.getEngineByMimeType ("application/javascript");

下面的代碼將會(huì)打印出當(dāng)前的 JDK 所支持的所有腳本引擎:

ScriptEngineManager factory = new ScriptEngineManager();
for (ScriptEngineFactory available : factory.getEngineFactories()) {
  System.out.println(available.getEngineName());
  // 打印腳本具體名稱信息
  System.out.println(available.getNames());
}

即可看到 [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript] 等輸出,說明可執(zhí)行 Js 腳本

執(zhí)行Js腳本

啥也別說了,都知道要干嘛,來打印句 HelloWorld 再說:

public class RunJavaScript {
  public static void main(String[] args){
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName ("JavaScript");
    engine.eval("print('Hello World')");
  }
}

如果你的 Js 有語法錯(cuò)誤,就會(huì)拋出 javax.script.ScriptException 異常

如果我們要解釋一些更復(fù)雜的腳本語言,或者想在運(yùn)行時(shí)改變?cè)撃_本該如何做呢?腳本引擎支持一個(gè)重載的 eval 方法,它可以從一個(gè) Reader 讀入所需的腳本,或者得到 Js 文件的絕對(duì)路徑,直接用自帶的 load 函數(shù)讀?。?/p>

ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName ("JavaScript");
engine.eval(new Reader("HelloWorld.js"));


File file = new File(Main.class.getClassLoader().getResource("test.js").getFile());
engine.eval(new FileReader(file));

String scriptPath = Main.class.getClassLoader().getResource("test.js").getPath();
engine.eval("load('" + scriptPath + "')");

這里注意下 FileReader 中相對(duì)路徑到底是相對(duì)誰的(JVM 啟動(dòng)的位置),可使用 ClassLoader 讀取 src 下的文件

Java 程序?qū)?dòng)態(tài)的去讀取腳本文件并解釋執(zhí)行,這意味著,在程序運(yùn)行中你可以隨意修改 Js 文件里的代碼,會(huì)得到實(shí)時(shí)修改結(jié)果。

對(duì)于這一簡(jiǎn)單的 Hello World 腳本來說,IO 操作將比直接執(zhí)行腳本損失 20% 左右的性能(SE6 時(shí),個(gè)人測(cè)試),但他帶來的靈活性 — 在運(yùn)行時(shí)動(dòng)態(tài)改變代碼的能力,在某些場(chǎng)合是十分激動(dòng)人心的。

最后來看看完整的測(cè)試代碼:

package com.bfchengnuo.javascript;

import javax.script.*;
import java.io.FileNotFoundException;

/**
 * Created by 冰封承諾Andy on 2017/12/30.
 */
public class Main {
  public static void main(String[] args) throws ScriptException, NoSuchMethodException, FileNotFoundException {
    ScriptEngineManager manager = new ScriptEngineManager();

    System.out.println("當(dāng)前 JDK 支持的腳本語言引擎:");
    for (ScriptEngineFactory available : manager.getEngineFactories()) {
      System.out.println(available.getEngineName());
      System.out.println(available.getNames());
    }

    ScriptEngine engine = manager.getEngineByName("JavaScript");
    if (!(engine instanceof Invocable)) {
      System.out.println("Invoking methods is not supported.");
      return;
    }
    engine.eval("print('Hello World')");

    Invocable inv = (Invocable) engine;

    // File file = new File(Main.class.getClassLoader().getResource("test.js").getFile());
    // engine.eval(new FileReader(file));
    String scriptPath = Main.class.getClassLoader().getResource("test.js").getPath();
    engine.eval("load('" + scriptPath + "')");

    // 獲取對(duì)象
    Object calculator = engine.get("calculator");

    int x = 3;
    int y = 4;
    Object addResult = inv.invokeMethod(calculator, "add", x, y);
    Object subResult = inv.invokeMethod(calculator, "subtract", x, y);
    Object mulResult = inv.invokeMethod(calculator, "multiply", x, y);
    Object divResult = inv.invokeMethod(calculator, "divide", x, y);

    System.out.println(addResult);
    System.out.println(subResult);
    System.out.println(mulResult);
    System.out.println(divResult);
  }
}

對(duì)應(yīng)的 Js 文件:

var calculator = {};

calculator.add = function (n1, n2) { return n1 + n2};
calculator.subtract = function (n1, n2) {return n1 - n2};
calculator.multiply = function (n1, n2) {return n1 * n2};
calculator.divide = function (n1, n2) {return n1 / n2};

腳本語言與 Java 的通信

ScriptEngine 的 put 方法用于將一個(gè) Java 對(duì)象映射成一個(gè)腳本語言的變量?,F(xiàn)在有一個(gè) Java Class,它只有一個(gè)方法:

public class HelloWorld {
  String s = "Hello World";
  public void sayHello(){
    System.out.println(s);
  }
}

接下來就是讓 Js 使用這個(gè)類!還是看代碼最實(shí)在:

public class TestPut {
  public static void main(String[] args) throws ScriptException {
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("JavaScript");
    HelloWorld hello = new HelloWorld();
    engine.put("script_hello", hello);
    engine.eval("script_hello.sayHello()");
  }
}

首先我們實(shí)例化一個(gè) HelloWorld,然后用 put 方法將這個(gè)實(shí)例映射為腳本語言的變量 script_hello。那么我們就可以在 eval() 函數(shù)中像 Java 程序中同樣的方式來調(diào)用這個(gè)實(shí)例的方法。

使用 invokeFunction 來執(zhí)行 Js 函數(shù):

public class TestInv {
  public static void main(String[] args) throws Exception {
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("JavaScript");
    String script = "function say(first,second) { print(first +' '+ second); }";
    engine.eval(script);
    Invocable inv = (Invocable) engine;
    inv.invokeFunction("say", "Hello", "Tony");
  }
}

這里使用了 ScriptEngine 的兩個(gè)可選接口之一 : Invocable,Invocable 表示當(dāng)前的 engine 可以作為函數(shù)被調(diào)用。

這里我們將 engine 強(qiáng)制轉(zhuǎn)換為 Invocable 類型,使用 invokeFunction 方法將參數(shù)傳遞給腳本引擎。invokeFunction 這個(gè)方法使用了可變參數(shù)的定義方式,可以一次傳遞多個(gè)參數(shù),并且將腳本語言的返回值作為它的返回值。

Invocable 接口還有一個(gè)方法用于從一個(gè) engine 中得到一個(gè) Java Interface 的實(shí)例,它接受一個(gè) Java 的 Interface 類型作為參數(shù),返回這個(gè) Interface 的一個(gè)實(shí)例。

也就是說你可以完全用腳本語言來寫一個(gè) Java Interface 的所有實(shí)現(xiàn)!然后直接調(diào)用使用返回的實(shí)現(xiàn)類就可以了!

engine.eval(script);
Invocable inv = (Invocable) engine;
MaxMin maxMin = inv.getInterface(MaxMin.class);

java 處理js返回值

  • JDK11之前版本
package io.icefox;

import java.util.Map;
import java.util.TreeMap;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;

import jdk.nashorn.api.scripting.ScriptObjectMirror;

public class JSTest {
    public static ScriptEngine engine;
    private static String str;
    
    public static void main(String[] args) throws Exception {
        //獲取js引擎實(shí)例
        ScriptEngineManager sem = new ScriptEngineManager();
        engine=sem.getEngineByName("javascript");
        getJsValue();
        getObject();
        putValue();
        callJsFunction();
    }
    //該函數(shù)測(cè)試Java獲取JS變量值的能力
    public static void getJsValue() throws Exception{
        str = "  var msg='hello';          "
                + "  var number = 123;         "
                + "  var array=['A','B','C'];  "
                + "  var json={                "
                + "      'name':'pd',          "
                + "      'subjson':{           "
                + "           'subname':'spd'  "
                + "           ,'id':123        "
                + "           }                "
                + "      };                    ";
        //執(zhí)行語句
        engine.eval(str);
        str="msg+=' world';number+=5";
        //再次執(zhí)行
        engine.eval(str);
        //獲取js變量msg(String類型)
        System.out.println(engine.get("msg"));
        //獲取js變量msg(int類型)
        System.out.println(engine.get("number"));
        //獲取js變量array(數(shù)組)
        ScriptObjectMirror array=(ScriptObjectMirror) engine.get("array");
        //getSlot(int index)函數(shù)用于獲取下標(biāo)為index的值
        System.out.println(array.getSlot(0));
        //獲取js變量json(json類型)
        ScriptObjectMirror json=(ScriptObjectMirror) engine.get("json");
        //get(String key)函數(shù)用于鍵key的值
        System.out.println(json.get("name"));
        //獲取js變量subjson(嵌套json類型)
        ScriptObjectMirror subjson=(ScriptObjectMirror)json.get("subjson");
        System.out.println(subjson.get("subname"));
    }
    //該函數(shù)測(cè)試Java與js對(duì)象
    public static void getObject() throws Exception{
        str = "  var obj=new Object();     "
                + "  obj.info='hello world';   "
                + "  obj.getInfo=function(){   "
                + "        return this.info;   "
                + "  };                        ";
        engine.eval(str);
        //獲取對(duì)象
        ScriptObjectMirror obj=(ScriptObjectMirror) engine.get("obj");
        //輸出屬性
        System.out.println(obj.get("info"));
        System.out.println(obj.get("getInfo"));
        str="obj.getInfo()";
        //執(zhí)行方法
        System.out.println(engine.eval(str));
    }
    //java將變量導(dǎo)入js腳本
    public static void putValue() throws Exception{
        str="Math.pow(a,b)";
        Map<String, Object>input=new TreeMap<>();
        input.put("a",2);
        input.put("b",8);
        System.out.println(engine.eval(str,new SimpleBindings(input)));
    }
    //調(diào)用js函數(shù)
    public static void callJsFunction() throws Exception{
        engine.eval("function add (a, b) {return a+b; }");
        Invocable jsInvoke = (Invocable) engine;
        Object res = jsInvoke.invokeFunction("add", new Object[] { 10, 5 });
        System.out.println(res);
    }
 
}
  • JDK11之后版本
package io.icefox;

import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;

import java.util.Map;
import java.util.TreeMap;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;


public class JSTest {
    public static ScriptEngine engine;
    private static String str;
    //該函數(shù)測(cè)試Java獲取JS變量值的能力
    public static void getJsValue() throws Exception{
        str = "  var msg='hello';          "
                + "  var number = 123;         "
                + "  var array=['A','B','C'];  "
                + "  var json={                "
                + "      'name':'pd',          "
                + "      'subjson':{           "
                + "           'subname':'spd'  "
                + "           ,'id':123        "
                + "           }                "
                + "      };                    ";
        //執(zhí)行語句
        engine.eval(str);
        str="msg+=' world';number+=5";
        //再次執(zhí)行
        engine.eval(str);
        //獲取js變量msg(String類型)
        System.out.println(engine.get("msg"));
        //獲取js變量msg(int類型)
        System.out.println(engine.get("number"));
        //獲取js變量array(數(shù)組)
        ScriptObjectMirror array=(ScriptObjectMirror) engine.get("array");
        //getSlot(int index)函數(shù)用于獲取下標(biāo)為index的值
        System.out.println(array.getSlot(0));
        //獲取js變量json(json類型)
        ScriptObjectMirror json=(ScriptObjectMirror) engine.get("json");
        //get(String key)函數(shù)用于鍵key的值
        System.out.println(json.get("name"));
        //獲取js變量subjson(嵌套json類型)
        ScriptObjectMirror subjson=(ScriptObjectMirror)json.get("subjson");
        System.out.println(subjson.get("subname"));
    }
    //該函數(shù)測(cè)試Java與js對(duì)象
    public static void getObject() throws Exception{
        str = "  var obj=new Object();     "
                + "  obj.info='hello world';   "
                + "  obj.getInfo=function(){   "
                + "        return this.info;   "
                + "  };                        ";
        engine.eval(str);
        //獲取對(duì)象
        ScriptObjectMirror obj=(ScriptObjectMirror) engine.get("obj");
        //輸出屬性
        System.out.println(obj.get("info"));
        System.out.println(obj.get("getInfo"));
        str="obj.getInfo()";
        //執(zhí)行方法
        System.out.println(engine.eval(str));
    }
    //java將變量導(dǎo)入js腳本
    public static void putValue() throws Exception{
        str="Math.pow(a,b)";
        Map<String, Object>input=new TreeMap<>();
        input.put("a",2);
        input.put("b",8);
        System.out.println(engine.eval(str,new SimpleBindings(input)));
    }
    //調(diào)用js函數(shù)
    public static void callJsFunction() throws Exception{
        engine.eval("function add (a, b) {return a+b; }");
        Invocable jsInvoke = (Invocable) engine;
        Object res = jsInvoke.invokeFunction("add", new Object[] { 10, 5 });
        System.out.println(res);
    }
    public static void main(String[] args) throws Exception {
        //獲取js引擎實(shí)例
        ScriptEngineManager sem = new ScriptEngineManager();
        engine=sem.getEngineByName("javascript");
        getJsValue();
        getObject();
        putValue();
        callJsFunction();
    }
}
  • JDK11之后移除了
jdk.nashorn.api.scripting.ScriptObjectMirror

使用JDK15之后版本需要添加maven依賴

使用org.openjdk.nashorn.api.scripting.ScriptObjectMirror

  <dependency>
      <groupId>org.openjdk.nashorn</groupId>
      <artifactId>nashorn-core</artifactId>
      <version>15.3</version>
  </dependency>

其他

其他的還可以對(duì) Js 進(jìn)行編譯、在 Js 中調(diào)用 Java 的代碼,但感覺用的不多,最常用的還是 Java 調(diào)用 Js 的方法

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 如何在Redis中實(shí)現(xiàn)分頁排序查詢過程解析

    如何在Redis中實(shí)現(xiàn)分頁排序查詢過程解析

    這篇文章主要介紹了如何在Redis中實(shí)現(xiàn)分頁排序查詢過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 深入了解java中的逃逸分析

    深入了解java中的逃逸分析

    這篇文章主要介紹了深入了解java中的逃逸分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 用Maven插件生成Mybatis代碼的實(shí)現(xiàn)方法

    用Maven插件生成Mybatis代碼的實(shí)現(xiàn)方法

    本文主要介紹 Maven插件生成Mybatis代碼,現(xiàn)在做開發(fā)的朋友有好多用Maven 來管理代碼,這里給大家舉個(gè)例子,有需要的同學(xué)可以看下
    2016-07-07
  • Java輸入年份和月份判斷多少天實(shí)例代碼

    Java輸入年份和月份判斷多少天實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Java輸入年度和月份判斷多少天的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • java?LeetCode普通字符串模擬題解示例

    java?LeetCode普通字符串模擬題解示例

    這篇文章主要為大家介紹了java?LeetCode普通字符串模擬題解示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • java 在觀察者模式中使用泛型T的實(shí)例

    java 在觀察者模式中使用泛型T的實(shí)例

    下面小編就為大家?guī)硪黄猨ava 在觀察者模式中使用泛型T的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟記錄

    SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟記錄

    MinIO是一個(gè)基于Apache License v2.0開源協(xié)議的對(duì)象存儲(chǔ)服務(wù),它兼容亞馬遜S3云存儲(chǔ)服務(wù)接口,非常適合于存儲(chǔ)大容量非結(jié)構(gòu)化的數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合Minio實(shí)現(xiàn)上傳文件的完整步驟,需要的朋友可以參考下
    2022-05-05
  • Dependency ‘XXX:‘ not found問題的三步解決

    Dependency ‘XXX:‘ not found問題的三步解決

    這篇文章主要介紹了Dependency ‘XXX:‘ not found問題的三步解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java通過URLClassLoader類加載器加載外部jar代碼示例

    java通過URLClassLoader類加載器加載外部jar代碼示例

    ClassLoader翻譯過來就是類加載器,普通的java開發(fā)者其實(shí)用到的不多,但對(duì)于某些框架開發(fā)者來說卻非常常見,下面這篇文章主要給大家介紹了關(guān)于java通過URLClassLoader類加載器加載外部jar的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • SpringBoot配置開發(fā)環(huán)境的詳細(xì)步驟(JDK、Maven、IDEA等)

    SpringBoot配置開發(fā)環(huán)境的詳細(xì)步驟(JDK、Maven、IDEA等)

    文章介紹了如何配置SpringBoot開發(fā)環(huán)境,包括安裝JDK、Maven和IDEA,并提供了詳細(xì)的步驟和配置方法,感興趣的朋友一起看看吧
    2024-12-12

最新評(píng)論