JAVA执行javascript方法-阿里云开发者社区

开发者社区> 蒋固金> 正文

JAVA执行javascript方法

简介:
+关注继续查看

之前在一次机缘巧合的情况下,需要时用JAVA执行js方法,查阅了一些文档,找到了相关解决方法,这里和大家分享一下。
在JDK1.6中为我们提供了一个ScriptEngineManager类,ScriptEngineManager 为 ScriptEngine 类实现一个发现和实例化机制,还维护一个键/值对集合来存储所有 Manager 创建的引擎所共享的状态。此类使用服务提供者机制枚举所有的 ScriptEngineFactory 实现。
ScriptEngineManager 提供了一个方法,可以返回一个所有工厂实现和基于语言名称、文件扩展名和 mime 类型查找工厂的实用方法所组成的数组。
键/值对的 Bindings(即由管理器维护的 “Global Scope”)对于 ScriptEngineManager 创建的所有 ScriptEngine 实例都是可用的。Bindings 中的值通常公开于所有脚本中。

通过上面的描述,我们就应该知道了,需要时用到的类为ScriptEngineManagerScriptEngine

我们先来看一下ScriptEngineManager

构造方法如下:

方法名 说明
ScriptEngineManager() 如果调用者可访问线程上下文 ClassLoader,则调用此构造方法的效果与调用 ScriptEngineManager(Thread.currentThread().getContextClassLoader()) 相同
ScriptEngineManager(ClassLoader loader) 此构造方法使用服务调用者机制加载对于给定 ClassLoader 可见的 ScriptEngineFactory 实现

方法摘要如下:

返回值 方法名 说明
Object get(String key) 获取 Global Scope 中指定键的值
Bindings getBindings() getBindings
ScriptEngine getEngineByExtension(String extension) 查找并创建一个给定扩展的 ScriptEngine
ScriptEngine getEngineByMimeType(String mimeType) 查找并创建一个给定 mime 类型的 ScriptEngine
ScriptEngine getEngineByName(String shortName) 查找并创建一个给定名称的 ScriptEngine
List<ScriptEngineFactory> getEngineFactories() 返回一个数组,该数组的元素是发现机制找到的所有 ScriptEngineFactory 类的实例
void put(String key, Object value) 设置 Global Scope 中指定的键/值对
void registerEngineExtension(String extension, ScriptEngineFactory factory) 注册一个 ScriptEngineFactory 来处理扩展
void registerEngineMimeType(String type, ScriptEngineFactory factory) 注册一个 ScriptEngineFactory 来处理 mime 类型。
void registerEngineName(String name, ScriptEngineFactory factory) 注册一个ScriptEngineFactory 来处理语言名称
void setBindings(Bindings bindings) setBindings 存储 globalScope 字段中的指定 Bindings

我们首先来看一下,JDK为我们提供了哪些可用的脚本引擎工厂,写一段代码测试一下:

@Test
public void getScriptEngineFactory()
{
   ScriptEngineManager manager = new ScriptEngineManager();
   List<ScriptEngineFactory> factories = manager.getEngineFactories();
   for (ScriptEngineFactory factory : factories)
   {
      System.out.println(factory.getNames());
   }
}

运行结果如下:

[nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript]

通过控制台输出的结果,我们知道JDK已经为我们实现了js相关的脚本引擎,我们直接使用就可以了,解决了引擎的问题,下面我们再来看看脚本引擎如何使用,这就需要ScriptEngine了。

ScriptEngine 是基础接口,该接口的方法在此规范的每个实现中都必须具有完整的功能。
这些方法提供基本的脚本功能。为这个简单接口编写的应用程序应该对每个实现稍做修改就能够运行。这包括执行脚本的方法,以及设置和获取值的方法。
这些值是两种类型的键/值对。组成第一种类型的键/值对中的键是此规范或个别实现中保留和定义的键。包含保留键的键/值对中的值具有指定的含义。
另一种类型由那些创建 Java 语言 Bindings 的键/值对组成,值通常通过相应键或其装饰的形式用脚本表示。

方法摘要如下:

返回值 方法名 说明
Bindings createBindings() 返回一个未初始化的 Bindings
Object eval(Reader reader) 除了脚本的源是以 Reader 形式提供的外,与 eval(String) 相同
Object eval(Reader reader, Bindings n) 除了脚本的源是以 Reader 形式提供的外,与 eval(String, Bindings) 相同
Object eval(Reader reader, ScriptContext context) 与 eval(String, ScriptContext) 相同,其中脚本的源是从 Reader 读取的
Object eval(String script) 执行指定的脚本
Object eval(String script, Bindings n) 执行脚本,脚本执行期间使用 Bindings 参数作为 ScriptEngine 的 ENGINE_SCOPE Bindings
Object eval(String script, ScriptContext context) 立即执行脚本,该脚本的源是作为第一个参数传递的 String
Object get(String key) 获取在此引擎的状态中设置的值
Bindings getBindings(int scope) 返回指定值的范围
ScriptContext getContext() 返回 ScriptEngine 的默认 ScriptContext,在没有指定 ScriptContext 时,该 ScriptEngine 的 Bindings、Reader 和 Writer 被用于脚本执行
ScriptEngineFactory getFactory() 返回此 ScriptEngine 所属的类的 ScriptEngineFactory
void put(String key, Object value) 设置 ScriptEngine 的状态中的键/值对,它创建一个将在脚本执行中使用或者以其他方式使用的 Java Language Binding,具体取决于该键是否被保留
void setBindings(Bindings bindings, int scope) 设置将由脚本使用的指定值的范围。
void setContext(ScriptContext context) 设置 ScriptEngine 的默认 ScriptContext,在没有指定 ScriptContext 时,该 ScriptEngine 的 Bindings、Reader 和 Writer 被用于脚本执行

下面我们通过代码来演示具体的使用方法

首先我们先来看一下如何执行一段简单的js表达式:

@Test
public void invokeExpression() throws ScriptException
{
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("js");
   String js = "1 + 2";
   Integer result = (Integer) engine.eval(js);
   System.out.println(result);
}

通过这段代码,我们很容易的就实现了java执行js的一段表达式。
在java中,我们不仅可以运行js的表达式,我们还可以执行js函数

@Test
public void invokeFunction() throws ScriptException, NoSuchMethodException
{
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("js");
   String js = "function welcom(){return 'welcom';}";
   engine.eval(js);
   Invocable invocable = (Invocable) engine;
   String result = (String) invocable.invokeFunction("welcom");
   System.out.println(result);
}

这里我们用到了Invocable接口,Invocable由 ScriptEngines 实现的可选接口,该 ScriptEngines 的方法允许在以前执行过的脚本中调用程序。当然啦,我们不仅能执行函数,还可以传递参数:

@Test
   public void invokeFunctionWithParam() throws ScriptException, NoSuchMethodException
{
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("js");
   String js = "function welcom(name){return 'welcom ' + name;}";
   engine.eval(js);
   Invocable invocable = (Invocable) engine;
   String result = (String) invocable.invokeFunction("welcom", "jianggujin");
   System.out.println(result);
}

除此之外,我们还可以将java对象注入到js代码中运行:

@Test
public void inject() throws ScriptException, NoSuchMethodException
{
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("js");
   Date date = new Date();
   System.out.println(date.getTime());
   engine.put("date", date);
   String js = "function getTime(){return date.getTime();}";
   engine.eval(js);
   Invocable invocable = (Invocable) engine;
   Long result = (Long) invocable.invokeFunction("getTime");
   System.out.println(result);
}

是不是很神奇呢?下面再介绍一种更神奇的,java通过线程启动js函数:

public void runThread() throws ScriptException, NoSuchMethodException
{
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("js");
   engine.put("out", System.out);
   String js = "var obj=new Object();obj.run=function(){out.println('thread...')}";
   engine.eval(js);
   Object obj = engine.get("obj");
   Invocable inv = (Invocable) engine;
   Runnable r = inv.getInterface(obj, Runnable.class);
   Thread t = new Thread(r);
   t.start();
}

好了,到这里java运行js的方法已经介绍的差不多了,下面贴出完整的测试代码:

import java.util.Date;
import java.util.List;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

/**
 * 运行javascript
 * 
 * @author jianggujin
 *
 */
public class RunJavascript
{

   public void getScriptEngineFactory()
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      List<ScriptEngineFactory> factories = manager.getEngineFactories();
      for (ScriptEngineFactory factory : factories)
      {
         System.out.println(factory.getNames());
      }
   }

   public void invokeExpression() throws ScriptException
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("js");
      String js = "1 + 2";
      Integer result = (Integer) engine.eval(js);
      System.out.println(result);
   }

   public void invokeFunction() throws ScriptException, NoSuchMethodException
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("js");
      String js = "function welcom(){return 'welcom';}";
      engine.eval(js);
      Invocable invocable = (Invocable) engine;
      String result = (String) invocable.invokeFunction("welcom");
      System.out.println(result);
   }

   public void invokeFunctionWithParam() throws ScriptException, NoSuchMethodException
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("js");
      String js = "function welcom(name){return 'welcom ' + name;}";
      engine.eval(js);
      Invocable invocable = (Invocable) engine;
      String result = (String) invocable.invokeFunction("welcom", "jianggujin");
      System.out.println(result);
   }

   public void inject() throws ScriptException, NoSuchMethodException
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("js");
      Date date = new Date();
      System.out.println(date.getTime());
      engine.put("date", date);
      String js = "function getTime(){return date.getTime();}";
      engine.eval(js);
      Invocable invocable = (Invocable) engine;
      Long result = (Long) invocable.invokeFunction("getTime");
      System.out.println(result);
   }

   public void runThread() throws ScriptException, NoSuchMethodException
   {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("js");
      engine.put("out", System.out);
      String js = "var obj=new Object();obj.run=function(){out.println('thread...')}";
      engine.eval(js);
      Object obj = engine.get("obj");
      Invocable inv = (Invocable) engine;
      Runnable r = inv.getInterface(obj, Runnable.class);
      Thread t = new Thread(r);
      t.start();
   }

   public static void main(String[] args) throws NoSuchMethodException, ScriptException
   {
      new RunJavascript().runThread();
   }

}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
最全总结 JavaScript Array 方法详解--《前端那些事》
我们在日常开发中,与接口打交道最多了,前端通过访问后端接口,然后将接口数据二次处理渲染到页面当中。 二次处理的过程是 考验 `Coder` 对 `Array` 是否熟练 以及 在 何种 场景下使用哪种方法处理最优 。
77 0
javascript系列之执行上下文
原文:javascript系列之执行上下文       写在前面:一 直想系统的总结一下学过的javascript知识,喜欢这门语言也热爱这门语言。未来想从事前端方面的工作,提前把自己的知识梳理一下。
745 0
25个JavaScript数组方法代码示例
摘要: 通过代码掌握数组方法。 原文:通过实现25个数组方法来理解及高效使用数组方法(长文,建议收藏) 译者:前端小智 Fundebug经授权转载,版权归原作者所有。 要在给定数组上使用方法,只需要通过[].方法名即可,这些方法都定义在 Array.prototype 对象上。
3419 0
shell java 执行
  java shell 命令  /** * * @author baoyou E-mail:curiousby@163.com * @version 2016年11月2日 下午1:54:49 * desc: */ public class ShellPro...
595 0
JavaScript异步精讲,让你更加明白Js的执行流程!
JavaScript异步精讲,让你更加明白Js的执行流程! 问题点 什么是单线程,和异步有什么关系 什么是 event-loop jQuery的Deferred Promise 的基本使用和原理 async/await(和 Promise的区别、联系) 一、什么是单线程,和异步有什么关系 单线程.
1828 0
20.Eclipse下Ndk开发(pthread开启线程调用Java方法)
本项目最终的目的是在pthread线程中,调用Java一个工具类得到多个uuid,然后调用类中另一个方法弹出toast,实现在c中获取安卓上下文对象Context 编译native方法,生成头文件的一系列过程不再赘述,直接上代码,都在注释中 PosixUtils: package com.
979 0
java方法重写和super关键字
//java方法重写和super关键字 //在继承中,其实就是子类定义了和父类同名的方法 //就是方法,属性都是相通的 //重写限制: //被子类重写的方法不能拥有比父类方法更加严格的权限 //super:强行调用父类方法的执行 /*重载和重写的区别? * 重载是发生在一个类中 对权限没...
732 0
+关注
115
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载