javascript
rhino java api demo_javascript与java的相互调用,纯java的javascript引擎rhino(转载)
1、下載Rhino安裝包,下載地址:官網(wǎng)http://www.mozilla.org/rhino。
2、rhino環(huán)境配置,把解壓出來的js.jar文件加入到系統(tǒng)的環(huán)境變量classpath
3、在命令提示符窗口下,調(diào)用javascript引擎,如:java org.mozilla.javascript.tools.shell.Main,即可進(jìn)入js shell.
4、將javascript代碼文件加載到引擎的內(nèi)存緩沖區(qū)中,如:
load("C:/ws/job/vqq1.0/WebRoot/js/mergeJsFile.js");
5、執(zhí)行合并操作,會一些相關(guān)js文件合并到一個js文件中,以減少瀏覽器對服務(wù)器端發(fā)出的http請求,提高性能問題。
如:runMerge(parameter1,parameter2, .., ...)
6、為了加快js文件運(yùn)行的速度,可以把它編譯為class文件,
compile:
java org.mozilla.javascript.tools.jsc.Main C:/ws/job/vqq1.0/WebRoot/js/mergeJsFile.js
編譯產(chǎn)生mergeJsFile.class文件,然后直接執(zhí)行class文件,java mergeJsFile.
Rhino的特點(diǎn)如下:
JavaScript 1.5的全部特性
◆ 允許使用腳本直接操作Java
◆ 提供JavaScript Shell執(zhí)行其它JavaScript腳本
◆ 提供JavaScript編譯器將JavaScript源程序轉(zhuǎn)換成Java類文件
Rhino語言特點(diǎn)
Java是一種面對對象的編譯型語言。它首先將源代碼編譯成二進(jìn)制字節(jié)碼(bytecode),然后依賴各種不同平臺上的虛擬機(jī)來解釋執(zhí)行字節(jié)碼,從而實(shí)現(xiàn)了“一次編譯、到處執(zhí)行”的跨平臺特性。
JavaScript是一種動態(tài)、弱類型、基于原型的客戶端腳本語言。JavaScript 包括一個基于對象的 API,稱為文檔對象模型(Document Object Model)或 DOM,用以訪問和操作 Web 頁面的內(nèi)容,給HTML網(wǎng)頁添加動態(tài)功能。
Rhino是一個介于Java與JavaScript之間的語言。它的基礎(chǔ)是 Java 語言,這使得它簡單易學(xué),但相比于JavaScript腳本語言來說,它又太過復(fù)雜。不過,Rhino 的主要缺點(diǎn)也正是它的強(qiáng)大之處,Rhino 是一種輕量級的、功能強(qiáng)大的腳本語言。Rhino 使用原型而不是類,這使它比很多腳本語言更適合開發(fā) GUI 應(yīng)用程序,在考慮性能和風(fēng)格等因素時更是如此。
Rhino語言特點(diǎn)的優(yōu)缺點(diǎn)
一方面,作為一種動態(tài)類型的、基于原型的腳本語言,Rhino借用了很多JavaScript語法。比如,Rhino不再使用語句結(jié)束符( ; ),放寬了變量聲明規(guī)則,并且極大地簡化了修改和檢索對象屬性的語法。另一方面,作為JavaScript 的Java實(shí)現(xiàn),Rhino語法非常類似于Java編程語言。比如,Rhino采用了與 Java 編程語言相似的循環(huán)和條件結(jié)構(gòu),并且遵循類似的語法模式來表示這些結(jié)構(gòu)。
Rhino 和 Java 語言之間有一些顯著的區(qū)別。Rhino 是一種基于原型的(prototype-based)語言,而不是一種基于類的(class-based)語言。Rhino中,函數(shù)和變量的聲明中看不到 類型,取而代之的是,使用 function關(guān)鍵字聲明函數(shù),使用 var關(guān)鍵字聲明局部變量。
Rhino的原始想法是將JavaScript 編譯成Java字節(jié)碼執(zhí)行,即采用編譯執(zhí)行的方式。由于JVM存在垃圾收集、編譯和裝載過程的開銷過大等限制,Rhino采用了解釋執(zhí)行的方式。
Rhino支持的腳本語言
在可以找到官方的腳本引擎的實(shí)現(xiàn)項(xiàng)目。這一項(xiàng)目基于BSD License ,表示這些腳本引擎的使用將十分自由。目前該項(xiàng)目已對包括 Groovy, JavaScript, Python, Ruby, PHP 在內(nèi)的二十多種腳本語言提供了支持。這一支持列表還將不斷擴(kuò)大。
在 Mustang 中對腳本引擎的檢索使用了工廠模式。首先需要實(shí)例化一個工廠 —— ScriptEngineManager。
// create a script engine manager
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");
下面的代碼將會打印出當(dāng)前的 JDK 所支持的所有腳本引擎
ScriptEngineManager factory = new ScriptEngineManager();
for (ScriptEngineFactory available : factory.getEngineFactories()) {
System.out.println(available.getEngineName());
}
JavaScript操縱Java對象
1. Rhino如何訪問Java包與類文件
Java語法規(guī)定,任何代碼都必須以class文件的形式存在,而每個class文件必須屬于一個package,默認(rèn)為default。而JavaScript并沒有類似package的層級結(jié)構(gòu)概念,那么如何使用Rhino訪問Java包呢?
Rhino定義了一個top-level變量Packages。變量Packages對應(yīng)的所有屬性均對應(yīng)Java包名。比如,我們需要訪問某一個Java的Package com.example,輸入如下:
js> Packages.com.example
剛才演示了如何通過js shell訪問Java包,訪問Java類的方式類似。假如我們需要訪問標(biāo)準(zhǔn)的Java 文件類java.io.File,如下。
js> java.io.File
或者,為避免輸入全名,我們先導(dǎo)入包,然后輸入Class類名,如下:
js> importPackage(java.io)
js>File
這里的importPackage(java.io),在效果上等價于Java聲明import java.io.*; 不同的是,Java會隱式import java.lang.*,而Rhino不會。因?yàn)镽hino定義的對象Boolean, Math, Number, Object, String等與Java語法完全不同,兩者無法等價。
2. Rhino如何與Java對象交互
與Java類似,Rhino使用new操作符創(chuàng)建對象。
js> new java.util.Date()
Thu May 06 16:19:04 CST 2011
可以使用JavaScript變量存儲Java對象,并調(diào)用其方法,如下:
js> f = new java.io.File("sample.txt")
sample.txt
js> f.isDirectory()
false
對于static方法與變量,調(diào)用如下:
js> java.lang.Math.PI
3.141592653589793
js> java.lang.Math.cos(0)
1
在JavaScript中,方法本身就是對象,這一點(diǎn)與Java不同。我們可以通過下列方式查看方法的重載:
js> f.listFiles
function listFiles() {/*
java.io.File[] listFiles()
java.io.File[] listFiles(java.io.FilenameFilter)
java.io.File[] listFiles(java.io.FileFilter)
*/}
輸出中列出三個重載方法。第一個為無參函數(shù),第二與第三個對應(yīng)的參數(shù)分別為FilenameFilter與FileFilter。
另一個比較有意思的特點(diǎn)是通過構(gòu)造for..in,查看對象對應(yīng)的所有方法與變量。如下:
js> for (i in f) { print(i) }
屏幕輸出為:
exists
parentFile
mkdir
toString
wait
[44 others]
這里列出的方法一部分來自于父類,比如wait來自父類java.lang.Object。
對于JavaBean,Rhino也提供按名字訪問的簡單方式。比如,通過下面這種方式,我們就可以調(diào)用File對象的getName與isDirectory方法:
js> f.name
test.txt
js> f.directory
false
3. Rhino如何實(shí)現(xiàn)Java接口
JavaScript當(dāng)中,方法本身就是對象。下面我們通過JavaScript語法{propertyName: value}聲明一個JavaScript方法,并調(diào)用該方法如下:
js> obj = { run: function () { print("\nrunning"); } }
[object Object]
js> obj.run()
running
現(xiàn)在我們構(gòu)造一個JavaScript對象,實(shí)現(xiàn)Runnable接口。并將該對象作為參數(shù),構(gòu)造一個新的線程,并啟動該線程。
js> r = new java.lang.Runnable(obj);
adapter1@291aff
js> t = new java.lang.Thread(r)
Thread[Thread-0,5,main]
js> t.start()
js>
running
最后的js>提示符與新線程的打印輸出running的先后順序是隨機(jī)的,取決于線程的調(diào)度策略。
從后端的處理流程來講,Rhino首先為Runnable接口的實(shí)現(xiàn)類生成Java字節(jié)碼文件。然后調(diào)用JavaScript對象定義的Run方法。
4. Rhino如何創(chuàng)建Java 數(shù)組
Rhino使用Java的發(fā)射機(jī)制生成數(shù)組。下面是生成2個String對象的代碼:
js> array = java.lang.reflect.Array.newInstance(java.lang.String, 2);
[Ljava.lang.String;@a20892
js> array[0] = "Double"
Double
js> array[1] = "Life"
Life
js> array[0] + array[1]
DoubleLife
js>
5. Rhino如何捕獲與處理異常
與Java類似,Rhino使用try...catch關(guān)鍵字處理異常。
js> function classForName(name) {
try {
return java.lang.Class.forName(name);
} catch (e if e.javaException instanceof java.lang.ClassNotFoundException) {
print("Class " + name + " not found");
} catch (e if e.javaException instanceof java.lang.NullPointerException) {
print("Class name is null");
}
}
js> classForName("NonExistingClass");
Class NonExistingClass not found
js> classForName(null);
Class name is null
6. Rhino如何調(diào)用js文件
當(dāng)然,除了在命令行的方式,我們還可以使用操縱JavaScript文件。下面是一段JavaScript代碼,主要目的是判斷該數(shù)是否為質(zhì)數(shù)。代碼如下:
function isPrime (num)
{
if (num <= 1) {
print("Enter an integer no less than 2.")
return false
}
var prime = true
var sqrRoot = Math.round(Math.sqrt(num))
for (var n = 2; prime & n <= sqrRoot; ++n) {
prime = (num % n != 0)
}
return prime
}
我們保存文件為C:\isPrime.js。然后我們需要調(diào)用load方法加載該腳本。最后,我們可以調(diào)用isPrime方法來判斷是否為質(zhì)數(shù)。
js> load("C:/isPrime.js")
js> isPrime(33);
false
js> isPrime(31)
true
需要注意的是,注意:文件分隔符需要調(diào)整,是“/”而不是“\”。
剛才使用JavaScript操縱Java對象。接下來我們看看如何使用Java程序訪問JavaScript
Java對象操縱JavaScript
下面是一段Java代碼,用來運(yùn)行數(shù)學(xué)表達(dá)式。代碼如下:
package com.example;
import sun.org.mozilla.javascript.internal.Context;
import sun.org.mozilla.javascript.internal.Scriptable;
publicclass Test {
publicstaticvoid main(String[] args) {
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
String str = "3/(1+2)";
Object result = cx.evaluateString(scope, str, null, 1, null);
System.out.println(str + "=" + Context.toNumber(result));
} finally {
Context.exit();
}
}
}
運(yùn)行Java com.example.Test,輸出結(jié)果如下:
3/(1+2)=1.0
之所以是1.0而不是1,是因?yàn)镃ontext.toNumber(result)返回的類型為double。
另一個值得注意的是,這里import的package屬于JDK 6.0。
因此,在不需要Rhino提供的js.jar,該程序仍能獨(dú)立運(yùn)行。因?yàn)閞hino已經(jīng)是jdk 6.0 的正規(guī)軍了,即是它的一部分。
A Java program for running JavaScript scripts
import javax.script.*; import java.io.*; // Evaluate a file of JavaScript and print its result public class RunScript { public static void main(String[] args) throws IOException { // Obtain an interpreter or "ScriptEngine" to run the script. ScriptEngineManager scriptManager = new ScriptEngineManager( ); ScriptEngine js = scriptManager.getEngineByExtension("js"); // The script file we are going to run String filename = null; // A Bindings object is a symbol table for or namespace for the // script engine. It associates names and values and makes // them available to the script. Bindings bindings = js.createBindings( ); // Process the arguments. They may include any number of // -Dname=value arguments, which define variables for the script. // Any argument that does not begin with -D is taken as a filename for(int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.startsWith("-D")) { int pos = arg.indexOf('='); if (pos == -1) usage( ); String name = arg.substring(2, pos); String value = arg.substring(pos+1); // Note that all the variables we define are strings. // Scripts can convert them to other types if necessary. // We could also pass a java.lang.Number, a java.lang.Boolean // or any Java object or null. bindings.put(name, value); } else { if (filename != null) usage( ); // only one file please filename = arg; } } // Make sure we got a file out of the arguments. if (filename == null) usage( ); // Add one more binding using a special reserved variable name // to tell the script engine the name of the file it will be executing. // This allows it to provide better error messages. bindings.put(ScriptEngine.FILENAME, filename); // Get a stream to read the script. Reader in = new FileReader(filename); try { // Evaluate the script using the bindings and get its result. Object result = js.eval(in, bindings); // Display the result. System.out.println(result); } catch(ScriptException ex) { // Or display an error message. System.out.println(ex); } } static void usage( ) { System.err.println( "Usage: java RunScript [-Dname=value...] script.js"); System.exit(1); } }
A Java configuration file utility that interprets JavaScript expressions
import javax.script.*; import java.util.*; import java.io.*; /** * This class is like java.util.Properties but allows property values to * be determined by evaluating JavaScript expressions. */ public class Configuration { // Here is where we store name/value pairs of defaults. Map defaults = new HashMap( ); // Accessors for getting and setting values in the map public Object get(String key) { return defaults.get(key); } public void put(String key, Object value) { defaults.put(key, value); } // Initialize the contents of the Map from a file of name/value pairs. // If a value is enclosed in curly braces, evaluate it as JavaScript. public void load(String filename) throws IOException, ScriptException { // Get a JavaScript interpreter. ScriptEngineManager manager = new ScriptEngineManager( ); ScriptEngine engine = manager.getEngineByExtension("js"); // Use our own name/value pairs as JavaScript variables. Bindings bindings = new SimpleBindings(defaults); // Create a context for evaluating scripts. ScriptContext context = new SimpleScriptContext( ); // Set those Bindings in the Context so that they are readable // by the scripts but so that variables defined by the scripts do // not get placed into our Map object. context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE); BufferedReader in = new BufferedReader(new FileReader(filename)); String line; while((line = in.readLine( )) != null) { line = line.trim( ); // strip leading and trailing space if (line.length( ) == 0) continue; // skip blank lines if (line.charAt(0) == '#') continue; // skip comments int pos = line.indexOf(":"); if (pos == -1) throw new IllegalArgumentException("syntax: " + line); String name = line.substring(0, pos).trim( ); String value = line.substring(pos+1).trim( ); char firstchar = value.charAt(0); int len = value.length( ); char lastchar = value.charAt(len-1); if (firstchar == '"' && lastchar == '"') { // Double-quoted quoted values are strings defaults.put(name, value.substring(1, len-1)); } else if (Character.isDigit(firstchar)) { // If it begins with a number, try to parse a number try { double d = Double.parseDouble(value); defaults.put(name, d); } catch(NumberFormatException e) { // Oops. Not a number. Store as a string defaults.put(name, value); } } else if (value.equals("true")) // handle boolean values defaults.put(name, Boolean.TRUE); else if (value.equals("false")) defaults.put(name, Boolean.FALSE); else if (value.equals("null")) defaults.put(name, null); else if (firstchar == '{' && lastchar == '}') { // If the value is in curly braces, evaluate as JavaScript code String script = value.substring(1, len-1); Object result = engine.eval(script, context); defaults.put(name, result); } else { // In the default case, just store the value as a string. defaults.put(name, value); } } } // A simple test program for the class public static void main(String[] args) throws IOException, ScriptException { Configuration defaults = new Configuration( ); defaults.load(args[0]); Set> entryset = defaults.defaults.entrySet( ); for(Map.Entry entry : entryset) { System.out.printf("%s: %s%n", entry.getKey( ), entry.getValue( )); } } }
Compiling Scripts
// This is the text of the script we want to compile. String scripttext = "x * x"; // Get the script engine. ScriptEngineManager scriptManager = new ScriptEngineManager( ); ScriptEngine js = scriptManager.getEngineByExtension("js"); // Cast it to the Compilable interface to get compilation functionality. Compilable compiler = (Compilable)js; // Compile the script to a form that we can execute repeatedly. CompiledScript script = compiler.compile(scripttext); // Now execute the script five times, using a different value for the // variable x each time. Bindings bindings = js.createBindings( ); for(int i = 0; i < 5; i++) { bindings.put("x", i); Object result = script.eval(bindings); System.out.printf("f(%d) = %s%n", i, result); }
Invoking JavaScript Functions
// Obtain an interpreter or "ScriptEngine" to run the script ScriptEngineManager scriptManager = new ScriptEngineManager( ); ScriptEngine js = scriptManager.getEngineByExtension("js"); // Evaluate the script. We discard the result since we only // care about the function definition. js.eval("function f(x) { return x*x; }"); // Now, invoke a function defined by the script. try { // Cast the ScriptEngine to the Invokable interface to // access its invocation functionality. Invocable invocable = (Invocable) js; for(int i = 0; i < 5; i++) { Object result = invocable.invoke("f", i); // Compute f(i) System.out.printf("f(%d) = %s%n", i, result); // Print result } } catch(NoSuchMethodException e) { // This happens if the script did not define a function named "f". System.out.println(e); }
Implementing a Java interface with JavaScript code
import javax.script.*; import java.io.*; import java.awt.event.*; import javax.swing.*; public class Keys { public static void main(String[] args) throws ScriptException, IOException { // Obtain an interpreter or "ScriptEngine" to run the script. ScriptEngineManager scriptManager = new ScriptEngineManager( ); ScriptEngine js = scriptManager.getEngineByExtension("js"); // Evaluate the script. We discard the result since we only // care about the function definitions in it. js.eval(new FileReader("listener.js")); // Cast to Invocable and get an object that implements KeyListener. Invocable invocable = (Invocable) js; KeyListener listener = invocable.getInterface(KeyListener.class); // Now use that KeyListener in a very simple GUI. JFrame frame = new JFrame("Keys Demo"); frame.addKeyListener(listener); frame.setSize(200, 200); frame.setVisible(true); } }
Implementing an interface in JavaScript simply means defining a function with the same name as each method defined by the interface. Here, for example, is a simple script that implements?KeyListener:
function keyPressed(e) {
print("key pressed: " + String.fromCharCode(e.getKeyChar( )));
}
function keyReleased(e) {
/* do nothing */
}
function keyTyped(e) {
/* do nothing */
}
Note that the JavaScript?keyPressed( )?method defined here accepts ajava.awt.event.KeyEvent?object as its argument and actually invokes a method on that Java object. The next section explains how this is done.
總結(jié)
以上是生活随笔為你收集整理的rhino java api demo_javascript与java的相互调用,纯java的javascript引擎rhino(转载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面向数据共享的教育数据标准体系研究与建设
- 下一篇: Day7:一款无线抢答系统的设计思路