2019独角兽企业重金招聘Python工程师标准>>>
在有些情况下需要在java里面执行javascript,这时rhino就可以帮忙了。mozilla的一个开源产品。
官网https://developer.mozilla.org/en-US/docs/Rhino
之前的一篇博客http://my.oschina.net/yybear/blog/101493里面介绍的事件模块处理程序就有利用javascript定义eventHandler,然后解释javascript执行。
先看一个简单的应用:
public class JavaScriptHandle {
private Scriptable global;
private int optimizationLevel = -1; // 介于-1到9之间,负值表示使用解释性执行,不会生成class
private Script script;
void handle() {
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(optimizationLevel);
if (script == null) {
script = ctx.compileString("var str = 'xx'", "firstRhino", 0, null);
}
Scriptable scope = new NativeObject();
scope.setParentScope(global);
script.exec(ctx, scope);
} finally {
Context.exit();
}
}
public static void main(String[] args) {
JavaScriptHandle jsh = new JavaScriptHandle();
jsh.handle();
}
}
还是很简单的,只有传入一个javascript的字符串就可以了。
但是更多时候我们希望在javascript里面也能调用java。比如我们希望执行这样的javascript
var s ='xx';$console.print(s);
$console表示java里面的标准输出。
这时需要先创建一个类
public class ConsoleScriptable extends ScriptableObject {
private static final long serialVersionUID = 1L;
private PrintStream printStream;
public void setPrintStream(PrintStream printStream) {
this.printStream = printStream;
}
public ConsoleScriptable() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String getClassName() {
return ConsoleScriptable.class.getSimpleName();
}
@JSFunction
public static void print(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
print0(thisObj, args, false);
}
@JSFunction
public static void println(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
print0(thisObj, args, true);
}
private static void print0(Scriptable thisObj, Object[] args, boolean eol) {
PrintStream printStream = checkInstance(thisObj).printStream;
for (Object arg : args) {
printStream.print(Context.toString(arg));
}
if (eol) {
printStream.println();
}
}
private static ConsoleScriptable checkInstance(Scriptable obj) {
if (obj == null || !(obj instanceof ConsoleScriptable)) {
throw Context.reportRuntimeError("called on incompatible object");
}
return (ConsoleScriptable) obj;
}
这个类就是实现了$console打印字符的功能。使用时先要在rhino里面注册下这个类:
JavaScriptHandle() {
// 初始化
Context ctx = Context.enter();
global = ctx.initStandardObjects();
try {
ScriptableObject.defineClass(global, ConsoleScriptable.class);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
使用代码:
void handle() {
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(optimizationLevel);
if (script == null) {
script = ctx.compileString("$console.print('xx');", "firstRhino", 0, null);
}
Scriptable scope = new NativeObject();
scope.setParentScope(global);
// 将$console设置标准输出
ConsoleScriptable $console = (ConsoleScriptable) ctx.newObject(scope, ConsoleScriptable.class.getSimpleName());
$console.setPrintStream(System.out);
ScriptableObject.putProperty(scope, "$console", $console); // 设置属性
script.exec(ctx, scope);
} finally {
Context.exit();
}
}
这样javascript里面就可以使用$console了。