Rhino 使 JavaScript 应用程序更灵动(转载)
脚本语言有良好的快速开发,高效率的执行,解释而非编译执行等优点,并且具有与其他语言编写的组件之间强大的通信功能。JavaScript 一直是脚本语言中的领头羊,它是一门具有非常丰富特性的语言。除了浏览器之外,JavaScript 也可以应用在其他场合,比如服务器端程序中。Rhino 是使用 Java 语言实现的 JavaScript 引擎,本文将介绍如何利用 Rhino 来使您的应用程序提供 JavaScript 脚本的支持。
引言
JavaScript 与浏览器完美配合,使得 JavaScript 成为世界上最流行的语言之一。随着 Web 应用的发展,AJAX 功能实现越来越丰富,JavaScript 也越来越受到人们的关注。新一代浏览器正在不断崛起,HTML5 逐渐成形和发展壮大,JavaScript 也将发挥越来越重要的作用和价值。目前众多的浏览器如 IE8、FireFox4.0 等做出的调整重点基本是针对于 JavaScript 引擎的改进和完善,JavaScript 的受欢迎程度可见一斑。
以简单的方式快速完成某些复杂的事情通常是创造脚本语言的重要原则,使用脚本语言通常比 C、C++、Java 之类的语言要简单容易,这也使得脚本语言具有相对于其他程序语言的特性:良好的快速开发,高效率的执行,解释而非编译执行,和其它语言编写的程序组件之间通信功能很强大。
JavaScript 一直是脚本语言的领头羊,是一门具有非常丰富特性的语言,使用灵活方便,尤其是内置的轻量级数据类型 JSON 使得 JavaScript 更加强大。使得 JavaScript 除了可以在浏览器中运行,同样可以作为应用程序的一部分使用在其他领域。在应用程序中使用 JavaScript 脚本可以为用户提供自定义公式、自定义单据转换规则、自定义工作流等功能,同时具有以下优势:
- 使用灵活方便,有利于快速开发
- 不需要编译,更新后马上可以看到运行效果
- 代码轻量,同样的程序只需要五分之一至十分之一的代码量
Rhino 是开源的 JavaScript 引擎,是完全基于 Java 实现,几乎可以使用 JavaScript 完成 Java 所有的工作。它可以提供强大的计算能力,没有 I/O 的限制,可以将 JavaScript 编译成 Java 字节码,具有良好的速度和性能。在 Rhino 环境中既可以使用 JavaScript 脚本语言,同时也可以非常简单的使用 Java 语言的某些工具。Rhino 为我们提供了如下功能:
- 对 JavaScript 1.5 的完全支持
- 直接在 Java 中使用 JavaScript 的功能
- 一个 JavaScript shell 用于运行 JavaScript 脚本
- 一个 JavaScript 的编译器,用于将 JavaScript 编译成 Java 二进制文件
本文将向您介绍如何使用 Rhino JavaScript 引擎,以及如何在您的项目中嵌入 Rhino JavaScript 引擎。阅读本文需要对 Java 和 JavaScript 有一定的理解和体会,如果您对这方面了解不多的话,建议您在阅读本文之前多查阅一些相关资料。本文中简单介绍了如何使用交互模式调用 JS 解释器,如果您感觉本部分理解有困难,很有可能是您对于控制台的使用不是特别熟悉,建议您了解一下控制台的使用方式。希望本文可以给您的学习和工作提供一定的帮助。
Rhino 使用
Rhino 环境准备
从 Mazilla 网站上下载 Rhino 引擎(本文撰写基于最新的版本 Rhino-1.7R3),下载地址为 http://www.mozilla.org/rhino/。将软件包解压,可以得到 Rhino 源代码、文档、测试代码、样例以及一些小工具,利用这些我们便可以通过多种方式执行 JavaScript 脚本。
使用交互模式调用 JS 解释器
- 进入交互模式
进入交互模式有两种方式:使用 js.jar 文件实现和使用 org.mozilla.javascript.tools.shell 实现。
打开控制台,并切换 ja.jar 文件所在的目录,输入
java -jar js.jar
命令,便会出现解释器的版本信息,并进入带提示符 js> 的命令模式。或切换到 tools 编译后目录,输入
java org.mozilla.javascript.tools.shell.Main
,同样可以进入带提示符 js> 的命令模式。 - 加载 JavaScript 文件
创建简单的 JavaScript 文件 tools.js,其代码如下:
var tools = {};
tools.testPlus = function(num1 , num2){
return num1 + num2;
}在命令行中输入 load("C:/tools.js")
,完成 tools.js 文件的加载。注意在此处"/"和"\"是有区别的,不能换用。 - 测试 JavaScript 代码运行
在命令行中输入
tools.testPlus(1,2)
,显示执行结果为 3,证明 JavaScript 代码运行成功。 - 退出交互模式
退出交互模式可以按 Ctrl+Z(Windows 系统)或 Ctrl+D(Linux 或 Unix 系统)的方式退出,也可以调用
quit()
方法退出。
Java 嵌入开发
本部分将向您介绍如何将 Rhino JavaScript 引擎嵌入到您的项目中,从而使您的应用程序增加脚本的支持,提高灵活度。简单而言,Rhino 的作用在于构造一个 JavaScript 运行所需要的运行环境,亦即下面所用的关键词上下文 Context,下面一步步向您介绍具体使用方式。
- 引入 Rhino JavaScript 工具包
在您的 Java 项目中使用 Rhino JavaScript 引擎,首先要做的工作是要将其引入到您的项目中,所需要类都在 org.mozilla.javascript
命名空间下,
示例如下:import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable; - 进入上下文
在导入 Rhino JavaScript 的 Java 包之后,需要创建并进入 Context。本步骤的作用在于构造 JavaScript 的运行环境,Context 中储存了脚本执行的全局环境信息,示例代码如下:
Context cx = Context.enter();
构造 JavaScript 的运行环境非常的简单,只需要调用 Java 类 Context 的静态方法 enter 即可,而无需对 Context 类进行实例化,该方法将会返回 Context 的一个实例。
- 初始化标准对象
在使用 Rhino 执行脚本之前,必须初始化标准对象(Object,Function 等),示例代码如下:
Scriptable scope = cx.initStandardObjects();
作用域是 JavaScript 中一个相当重要的概念,在本步骤初始化的 scope 变量类似于构造了一个全局对象,而在整个运行过程中 JavaScript 的变量都会作为该对象的一部分,在下文中介绍的在 Java 中调用 JavaScript 变量就是通过该对象实现。初始化标准化对象,需要调用上下文实例的 initStandardObjects 方法,执行结果将会返回一个 Scriptable 实例化对象。
- 执行 JavaScript 脚本
当以上准备工作结束后,便可以正常的执行 JavaScript 脚本,示例代码如下:
Object result = cx.evaluateString(scope, string, error, num, null);
JavaScript 脚本的执行是使用上下文示例中的 evaluateString 方法,执行脚本字符串 string,当脚本中需要使用其它变量时,会在作用域 scope 中寻找所需要的变量,如果发生异常的话则会报告 error 错误信息和所在的行号 num,正确执行结束后会返回一个 Object 对象的运行结果。
- 输出运行的结果
JavaScript 没有独立的输入输出方法,必须借助于宿主环境的输入输出方法,这里使用 Java 的输出机制 System.out.println 方法,示例代码如下:
System.out.println(cx.toString(result));
- 结束上下文
结束上下文是每次使用 Rhino 结束后必须要做的工作,它将移除上下文和当前的线程并做垃圾回收。示例代码如下:
Context.exit();
在每次进入上下文后您都应该调用它退出方法,因为在使用过程中可能会产生异常,所以通常在调用 Context.enter() 进入上下文之后,将退出操作放入对应的 finally 块中。
- 在运行环境中导入 JavaScript 工具包
在系统开发过程中,我们经常会使用一些 JavaScript 工具包,如加密工具包等。而使用 Rhino 导入工具包也是非常的简单方便,只需要将工具包文件中的内容以字符的形式在上下文中运行,以后便可以使用对应的作用域中直接使用。示例代码如下:
Context ct = Context.enter();
Scriptable scope = ct.initStandardObjects();
String filename=System.getProperty("user.dir")+"/demo/test.js";
try {
LineNumberReader reader = new LineNumberReader(new FileReader(filename)); String temp = null;
StringBuffer sb = new StringBuffer();
while((temp = reader.readLine()) != null){
sb.append(temp).append("\n");
}
ct.evaluateString(scope, sb.toString(), null, 1, null);
Object result = ct.evaluateString(scope, "test();", null, 1, null);
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
} finally{
ct.exit();
}
Java 和 JavaScript 对象相互调用
从根本上讲在 Java 项目中嵌入 JavaScript 脚本引擎,最重要的一点是实现 Java 和 JavaScript 之间的数据共享,而使用 Rhino JavaScript 引擎我们不需要添加任何的代码和实现,便可以使用 Java 和 JavaScript 对象之间相互调用,例如在 JavaScript 脚本中可以十分方便的去调用 Java 的工具包,而在 Java 中又可以十分方便的去调用 JavaScript 脚本中的变量,从而实现二者之间的无缝结合,提高项目的灵活度,下面将从这两个方面去详细介绍实现方式。
- 在 JavaScript 脚本中使用 Java 对象
将 Java 部分代码或者功能实现作为 JavaScript 一部分,以脚本的方式执行,这种方式在极大程度上可以减少用户为解决个别问题而费尽脑筋。在 JavaScript 中可以直接使用 Java 对象,示例代码如下:
Context ct = Context.enter();
Scriptable scope = ct.initStandardObjects();
String str = "var test={};";
str += "test.call=function(){return 'Successful!';};";
str += "java.lang.System.out.println(test.call())";
ct.evaluateString(scope, str, null, 1, null);在上述实例代码中实现了在 JavaScript 代码中直接调用 Java 的输出方法,这种方式可能从感觉上不是很舒服,因为需要明确定义 Java 的命名空间等信息。另外,也可以将 Java 对象转换为 JavaScript 对象,并添加到运行环境中,需要添加额外的代码去实现,这种方式有点像 Java 工具包的导入,示例代码如下:
Context ct = Context.enter();
Scriptable scope = ct.initStandardObjects();
Object out = Context.javaToJS(System.out, scope);
ScriptableObject.putProperty(scope, "out", out);
ct.evaluateString(scope, "out.println('Successful!')", null, 1, null); - 在 Java 中调用 JavaScript 脚本中的变量
在 Java 中若要取得 JavaScript 脚本的运行结果非常的简单,在前面的文字中我们已经探讨过,使用运行返回的结果即可。然而在项目开发中我们或许常常会希望获得一些额外的信息,比如运行过程中的一些临时信息,无法作为最终结果返回时,本部分将是您特别希望得到的,而本部分的实现十分简单,简单的几行代码便可以实现。示例代码如下:
Context ct = Context.enter();
Scriptable scope = ct.initStandardObjects();
ct.evaluateString(scope, "var test = 'Successful';", null, 1, null);
Object jsObject = scope.get("test" , scope);
if (jsObject == Scriptable.NOT_FOUND) {
System.out.println("test is not defined.");
} else {
System.out.println("test is " + Context.toString(jsObject));
}在上述的示例代码中,我们同样用到了 scope 变量,这个是 JavaScript 运行时的全局变量,您可以将它理解成为一个容器,里面包含了 JavaScript 运行过程中的所有信息,所以在您希望取得 JavaScript 过程中的某些信息时,请首先考虑该对象。
- 在 Java 中调用 JavaScript 脚本中的函数
在前文中我们已经向您展示了如何将 Java 代码以 JavaScript 脚本的方式运行,同样我们也可以将 JavaScript 脚本作为 Java 代码进行实现,这样可以使您的项目复用度极大提高,也将会使您在项目开发过程中更加得心应手,示例代码如下:
Context ct = Context.enter();
Scriptable scope = ct.initStandardObjects();
ct.evaluateString(scope,
"function test(name){return 'Successful!' + name;}", null, 1, null);
Object functionObject = scope.get("test" , scope);
if (!(functionObject instanceof Function)) {
System.out.println("test is undefined or not a function.");
} else {
Object testArgs[] = {"Ceven"};
Function test = (Function)functionObject;
Object result = test.call(ct, scope, scope, testArgs);
System.out.println(Context.toString(result));
}
结束语
正如引言中所说,JavaScript 脚本可以为我们的应用程序注入新鲜活力,在用户自定义方法和流程中将会发挥巨大的灵活性和价值。Rhino 是轻量级而又功能强大的 JavaScript 引擎,而且完全基于 Java 实现,与 Java 应用程序完美结合,将会成为 Java 应用程序开发首选工具。
参考资料
学习
- 访问 Mozilla 官方网站在线文档,了解更多 Rhino 的使用细节。
- 访问 脚本语言特性了解更多关于脚本语言的特性和价值。
- 访问 JavaScript 介绍和说明了解更多关于 JavaScript 的相关信息。
- developerWorks Java 技术专区:这里有数百篇关于 Java 编程各个方面的文章。
Rhino 使 JavaScript 应用程序更灵动(转载)的更多相关文章
- 一个尖括号能干什么,画一个笑脸开始(为了支持交互,它又增添了JavaScript。HTML页面也越来越臃肿。于是CSS便诞生了。API和核心代码的出现使HTML能够访问更复杂的软件功能--支持更高级的交互和云服务集成。这就是今天的HTML5)
一个尖括号 < 一个尖括号能干什么 < ? 你可以编出一顶帽子 <(:-p 或一张笑脸 :-> 再或者更直接一些 20世纪90年代初,html作为一种简单标记语言面世,用于在互 ...
- JavaScript的程序构成
JavaScript的程序构成主要从以下几方面做个总结:控制语句.函数 .事件驱动及事件处理,希望对读者有些帮助. 控制语句: if条件语句 基本格式 if(表述式) 语句段1: ...... els ...
- 了解 JavaScript 应用程序中的内存泄漏
简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许多功能无需考虑内存管理 ...
- Qone 正式开源,使 javascript 支持 .NET LINQ
Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzhang/qone 缘由 最近刚好修改了腾讯文档 Excel ...
- 大型JavaScript应用程序架构模式
11月中旬在伦敦举行的jQuery Summit顶级大会上有个session讲的是大型JavaScript应用程序架构,看完PPT以后觉得甚是不错,于是整理一下发给大家共勉. PDF版的PPT下载地址 ...
- (6)javascript的程序控制结构及语句-----(1)条件判断
程序控制结构及语句 编程就是将现实应用,转换为程序能够读得懂的语法语句.Javascript编程中对程序流程控制主要是通过条件判断语句.循环控制语句及continue.break来完成的,其中条件判断 ...
- 让你的ASP.NET Core应用程序更安全
让你的ASP.NET Core应用程序更安全 对于ASP.NET Core应用程序,除了提供认证和授权机制来保证服务的安全性,还需要考虑下面的一些安全因素: CSRF 强制HTTPS 安全的HTTP ...
- ASP.NET程序也能像WinForm程序一样运行[转载]
阅读目录 开始 操作方式 支持的ASP.NET程序类别 它也是个HTTP服务器 支持远程机器访问 不受限于Windows防火墙 尊重每个人的操作习惯 内置多标签浏览器支持 启动参数及配置文件 支持 . ...
- C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁
系列文章 C#开发奇技淫巧一:调试windows系统服务 C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件 C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁 程序目录的整理 ...
随机推荐
- 数据库比较工具DBCompareTool for Oracle 0.2.5发布
迁移数据库sql to oracle http://www.oracle.com/technetwork/cn/database/migration/connect-sqlserver-1945229 ...
- WCF揭秘学习笔记(3):使用DataContractSerializer
使用DataContractSerializer 终结点(包括地址.绑定.契约)可通过代码以编程方式添加到服务中.如: using(ServiceHost host =new ServiceHost( ...
- OGNL遍历list、map的常用三种方法
package com.mylife.po; public class User { private String uname; private String pwd; public String g ...
- Dynamics CRM 2011 权限管理
CRM系统基于角色的权限主要通过部门.角色.用户.团队来进行控制.每一个实体记录的所有者(Owner)必然是某一个用户或团队.一个用户或团队必然归属于一个且只归属于一个部门,但团队的成员即用户可以来自 ...
- Eutils用法总结
好久没更新了,这里都长草了... 总结下Eutils的用法,参考<E-utilities Quick Start>,没时间看英文的可以参考下. 简介 Eutils全称是The Entrez ...
- vuex语法精简(方便开发查阅)
vuex语法精简(方便开发查阅) store结构 state Getter Mutation actions vuex语法精简(方便开发查阅) 本文只是方便开发的时候快速查阅到相关语法,想看详细内容请 ...
- 全虚拟化和半虚拟化的区别 cpu的ring0~ring3又是什么概念?
ring0是指CPU的运行级别,ring0是最高级别,ring1次之,ring2更次之-- 拿Linux+x86来说, 操作系统(内核)的代码运行在最高运行级别ring0上,可以使用特权指令,控制中断 ...
- php自动生成mysql的触发代码。
如果公司里有上百个表要做触发器,如果手动写代码的话.很累,所以今天写了一个小程序, <?php $dbname = 'test';//数据库 $tab1 = 'user'; //执行的表 $ta ...
- 小米笔记本pro CPU GPU 做科学计算的算力对比
小米笔记本pro:15.6寸,i7-8850,16G,256G,GPU:MX150 测试对象Caffe,MNIST训练 使用纯CPU训练: 1.耗时:11分58秒 2.功耗:35W 使用GPU训练: ...
- HTTP --meta详解
meta是html语言head区的一个辅助性标签.也许你认为这些代码可有可无.其实如果你能够用好meta标签,会给你带来意想不到的效果,meta标签的作用有:搜索引擎优化(SEO),定义页面使用语言, ...