Rhino――一个可以在Java中操作和执行JS的框架
前段时间,在浏览javaeye论坛,看见有人征集如何在java中运行数学表达式。
结果方案五花八门:
1.jakarta commons JEXL.
2.Beanshell
3.Java Math Expression Parser jep
4.parse combinator jparsec
5.jdk 6.0的 script
6.利用SQL
7.自己写语法分析
如果自己写语法分析,没有个2000行估计搞不定。有人用sql来运行数学表达式,比较另类。
不过由于前段时间较深入的学习了一些java的javascript引擎,我给出的方案就是用javascript来计算了。
java中比较著名的js引擎当属mozilla开源的rhino,不过jdk6已经把它收归帐下,成了正规军。
- public?class?MathEval ??
- { ??
-
????public?static?void?main(String[]?args) ??
- ????{ ??
- ????????Context?cx?=?Context.enter(); ??
-
????????try??
- ????????{ ??
- ????????????Scriptable?scope?=?cx.initStandardObjects(); ??
-
????????????String?str?=?"9*(1+2)"; ??
-
????????????Object?result?=?cx.evaluateString(scope,?str,?null,?1,?null); ??
-
????????????double?res?=?Context.toNumber(result); ??
- ????????????System.out.println(res); ??
- ????????} ??
-
????????finally??
- ????????{ ??
- ????????????Context.exit(); ??
- ????????} ??
- ????} ??
- }??
下面总结一下前段时间学习rhino的心得(给自己的程序添加脚本功能,其实是很酷的):
一:环境配置及运行js脚本:
在 http://www.mozilla.org/rhino/ 下载rhino:
把js.jar加入系统CLASSPATH中
可以以交互模式调用js解释器:
java org.mozilla.javascript.tools.shell.Main
然后您应该会看到解释器的版本号,后面跟着提示符 js>
用法如下:
比如:有一个js文件:
D:\eclipse-workshop\rhinoExample\src\isPrime.js
内容如下:
js 代码
- function?isPrime?(num) ??
- { ??
-
????if?(num?<=?1)?{ ??
-
????????print("Please?enter?a?positive?integer?>=?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 ??
- }??
如何运行呢:
1:在命令行下键入:
java org.mozilla.javascript.tools.shell.Main
2:在js〉下键入:
load("D:/eclipse-workshop/rhinoExample/src/isPrime.js");
注意:是“/”而不是“\”
3:键入:
isPrime(77);
可看见返回结果为false。
键入:
isPrime(71);返回true
再给个例子,脚本如下:
- person?=?{ ??
-
??name:"Mike?Squillace", ??
- ??age:37, ??
-
??position:"software?engineer", ??
-
??getFirstName:function?()?{return?this.name.split("?")[0]} ??
- } ??
- person.getFirstName()??
js产生swing的例子:
load("D:/eclipse-workshop/rhinoExample/src/SwingApplication.js");
怎么样?看见效果没?是不是很强悍?其中SwingApplication.js是rhnio自带的例子。
Rhino还有一个js脚本的调试器:
Rhino JavaScript Debugger:
java org.mozilla.javascript.tools.debugger.Main [options] [filename.js] [script-arguments]
只须运行java org.mozilla.javascript.tools.debugger.Main,就可以看到调试器的界面了。
为了加快js文件运行的速度,可以把它编译为class文件:
compile:
java org.mozilla.javascript.tools.jsc.Main D:/eclipse-workshop/rhinoExample/src/FirstCompile.js
编译产生FirstCompile.class文件
在D:/eclipse-workshop/rhinoExample/src/下运行该class文件:
java FirstCompile
二:在实际应用中不可避免的需要遇到java代码如何和javascript脚本相互访问的问题:
这是一个最简单的例子:(liveConnect.js是rhnio自带的例子):
load("D:/eclipse-workshop/rhinoExample/src/liveConnect.js");
在给个复杂点的例子, 没有什么逻辑,纯技术展示,呵呵:
JSFunction.java:
java 代码
- package?co.test; ??
- ??
- import?org.mozilla.javascript.Function; ??
- ??
- public?class?JSFunction????
- { ??
-
?private?String?name;? ??
- ? ??
-
?private?Function?handle; ??
- ? ??
-
?public?void?setHandler(Function?func) ??
- ?{ ??
-
??this.handle?=?func; ??
- ?} ??
- ? ??
-
?public?Function?getHandler() ??
- ?{ ??
-
??return?this.handle; ??
- ?} ??
- ??
- ? ??
-
?public?JSFunction(String?s) ??
- ?{ ??
-
??this.name?=?s; ??
- ?}? ??
- ? ??
-
?public?static?void?print(String?s) ??
- ?{ ??
- ??System.out.println(s); ??
- ?} ??
- ??
-
?public?String?getName()?{ ??
-
??return?name; ??
- ?} ??
-
?public?void?setName(String?name)?{ ??
-
??this.name?=?name; ??
- ?} ??
- ??
- } ??
- ??
JSExploration.java:
java 代码
- package?co.test; ??
- ??
- import?java.io.FileReader; ??
- import?java.io.LineNumberReader; ??
- ??
- import?org.mozilla.javascript.Context; ??
- import?org.mozilla.javascript.Function; ??
- import?org.mozilla.javascript.Scriptable; ??
- ??
- public?class?JSExploration ??
- { ??
-
????private?Context?cx; ??
- ??
-
????private?Scriptable?scope; ??
- ??
-
????public?JSExploration() ??
- ????{ ??
-
????????this.cx?=?Context.enter(); ??
-
????????this.scope?=?cx.initStandardObjects(); ??
- ????} ??
- ??
-
????public?Object?runJavaScript(String?filename) ??
- ????{ ??
-
????????String?jsContent?=?this.getJsContent(filename); ??
-
????????Object?result?=?cx.evaluateString(scope,?jsContent,?filename,?1,?null); ??
-
????????return?result; ??
- ????} ??
- ??
-
????private?String?getJsContent(String?filename) ??
- ????{ ??
- ????????LineNumberReader?reader; ??
-
????????try??
- ????????{ ??
-
????????????reader?=?new?LineNumberReader(new?FileReader(filename)); ??
-
????????????String?s?=?null; ??
-
????????????StringBuffer?sb?=?new?StringBuffer(); ??
-
????????????while?((s?=?reader.readLine())?!=?null) ??
- ????????????{ ??
-
????????????????sb.append(s).append("\n"); ??
- ????????????} ??
-
????????????return?sb.toString(); ??
- ????????} ??
-
????????catch?(Exception?e) ??
- ????????{ ??
-
??????????????
- ????????????e.printStackTrace(); ??
-
????????????return?null; ??
- ????????} ??
- ????} ??
- ??
- ??
-
????public?Scriptable?getScope() ??
- ????{ ??
-
????????return?scope; ??
- ????} ??
- ??
-
????public?static?void?main(String[]?args) ??
- ????{ ??
-
????????String?filename?=?System.getProperty("user.dir")?+?"/jsmap.js"; ??
-
????????JSExploration?jsExploration?=?new?JSExploration(); ??
- ????????Object?result?=?jsExploration.runJavaScript(filename); ??
- ????????Scriptable?scope?=?jsExploration.getScope(); ??
-
????????Scriptable?obj?=?(Scriptable)?scope.get("obj",?scope); ??
-
????????System.out.println("obj.a?==?"?+?obj.get("a",?obj)); ??
-
????????Scriptable?b?=?(Scriptable)?obj.get("b",?obj); ??
-
????????System.out.println("b[0]?==?"?+?b.get(0,?b)); ??
-
????????Boolean?flag?=?(Boolean)?scope.get("flag",?scope); ??
- ????????System.out.println(flag); ??
- ??
-
????????Scriptable?myobj?=?(Scriptable)?scope.get("obj",?scope); ??
-
????????Boolean?myflag?=?(Boolean)?scope.get("flag",?scope); ??
- ????????System.out.println(myflag); ??
- ??
-
????????Scriptable?jsFunction?=?(Scriptable)?scope.get("jsFunction",?scope); ??
-
????????Function?fc?=?(Function)?jsFunction.get("handler",?jsFunction); ??
-
????????Object?isPrime?=?fc.call(Context.getCurrentContext(),?jsFunction,?fc,?new?Object[]?{?"this?is?my?test"?}); ??
- ????} ??
- } ??
- ??
js脚本:jsmap.js
js 代码
- var?swingNames?=?JavaImporter(); ??
- ??
- swingNames.importPackage(Packages.java.lang); ??
- swingNames.importPackage(Packages.co.test); ??
- ??
- obj?=?{a:1,?b:['x','y']} ??
- next?=?isPrime ??
- flag?=?isPrime(5) ??
- with?(swingNames)?{ ??
-
?System.out.println("in?javascript"); ??
-
?JSFunction.print("in?JSFunction"); ??
-
??jsFunction?=?new?JSFunction("lichunlei"); ??
-
?var?name?=?jsFunction.getName(); ??
-
?System.out.println("get?name?from?java?source:?"?+?name); ??
- ?jsFunction.setHandler(log);? ??
- }? ??
- ??
-
java.lang.System.out.println("not?use?swingNames"); ??
- function?isPrime?(num) ??
- { ??
-
?java.lang.System.out.println("in?isPrime(num)"); ??
-
????if?(num?<=?1)?{ ??
-
????????java.lang.System.out.println("Please?enter?a?positive?integer?>=?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 ??
- } ??
- ??
- function?log(msg) ??
- { ??
-
?java.lang.System.out.println("in?function?log:?"?+?msg); ??
- } ??
- ??
- ???