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

}
目录
相关文章
|
1月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
212 18
|
1月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
182 4
|
1月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
239 5
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
130 11
|
2月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
3月前
|
算法 Java
Java语言实现链表反转的方法
这种反转方法不需要使用额外的存储空间,因此空间复杂度为,它只需要遍历一次链表,所以时间复杂度为,其中为链表的长度。这使得这种反转链表的方法既高效又实用。
351 0
|
3月前
|
存储 Java 数据处理
Java映射操作:深入Map.getOrDefault与MapUtils方法
结合 `getOrDefault`方法的简洁性及 `MapUtils`的丰富功能,Java的映射操作变得既灵活又高效。合理地使用这些工具能够显著提高数据处理的速度和质量。开发人员可以根据具体的应用场景选择适宜的方法,以求在性能和可读性之间找到最佳平衡。
158 0
|
3月前
|
缓存 人工智能 NoSQL
Java中实现Token设置过期时间的方法
本文介绍了在Java应用中实现Token设置过期时间的多种方法,包括使用JWT和Redis缓存,并结合定时任务清理过期Token,以提升系统安全性与用户隐私保护。
411 0
|
3月前
|
算法 Java 开发者
Java 项目实战数字华容道与石头迷阵游戏开发详解及实战方法
本文介绍了使用Java实现数字华容道和石头迷阵游戏的技术方案与应用实例,涵盖GUI界面设计、二维数组操作、游戏逻辑控制及自动解法算法(如A*),适合Java开发者学习游戏开发技巧。
261 46
|
4月前
|
安全 Java API
Java 集合高级应用与实战技巧之高效运用方法及实战案例解析
本课程深入讲解Java集合的高级应用与实战技巧,涵盖Stream API、并行处理、Optional类、现代化Map操作、不可变集合、异步处理及高级排序等核心内容,结合丰富示例,助你掌握Java集合的高效运用,提升代码质量与开发效率。
244 0