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();
   }

}
目录
相关文章
|
16天前
|
Web App开发 JavaScript 前端开发
如何确保 Math 对象的方法在不同的 JavaScript 环境中具有一致的精度?
【10月更文挑战第29天】通过遵循标准和最佳实践、采用固定精度计算、进行全面的测试与验证、避免隐式类型转换以及持续关注和更新等方法,可以在很大程度上确保Math对象的方法在不同的JavaScript环境中具有一致的精度,从而提高代码的可靠性和可移植性。
|
15天前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
15天前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
15天前
|
JavaScript 前端开发
.js方法参数argument
【10月更文挑战第26天】`arguments` 对象为JavaScript函数提供了一种灵活处理参数的方式,能够满足各种不同的参数传递和处理需求,在实际开发中具有广泛的应用价值。
32 7
|
14天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
54 4
|
25天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
45 17
|
16天前
|
JavaScript 前端开发 图形学
JavaScript 中 Math 对象常用方法
【10月更文挑战第29天】JavaScript中的Math对象提供了丰富多样的数学方法,涵盖了基本数学运算、幂运算、开方、随机数生成、极值获取以及三角函数等多个方面,为各种数学相关的计算和处理提供了强大的支持,是JavaScript编程中不可或缺的一部分。
|
18天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
34 2
|
21天前
|
JavaScript 前端开发 Go
异步加载 JS 的方法
【10月更文挑战第24天】异步加载 JavaScript 是提高网页性能和用户体验的重要手段。通过使用不同的方法和技术,可以实现灵活、高效的异步加载 JavaScript。在实际应用中,需要根据具体情况选择合适的方法,并注意处理可能出现的问题,以确保网页能够正常加载和执行。
|
26天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3