在策略的計(jì)算部分,很多情況采用動態(tài)腳本語言來進(jìn)行,今天結(jié)合Java和JavaScript來進(jìn)行一個(gè)小小的演練,其實(shí)在Java中執(zhí)行JS并不是像想象的那樣隨心所欲,有些地方需要還是要做個(gè)轉(zhuǎn)彎的思考。

1、開始環(huán)境構(gòu)建
Java自JDK1.6以來,就支持JS的腳本執(zhí)行,首先通過初始化腳本引擎管理器,通過這個(gè)管理器獲取對應(yīng)腳本的執(zhí)行引擎,如下:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
到這個(gè)地方,這個(gè)engine對象我們就可以隨時(shí)隨地的使用,下面開始幻化吧
2、Hello World
先從一個(gè)基本的程序開始,輸出我們熟悉的Hello World
String script = "function hello(name) { return 'Hello,' + name;}";
engine.eval(script);
Invocable inv = (Invocable) engine;
String res = (String) inv.invokeFunction("hello", "World");
System.out.println("res:" + res);
第一行就是一個(gè)標(biāo)準(zhǔn)的JS函數(shù),入?yún)ame,返回Hello+name這樣一個(gè)形式
第二行就是把這個(gè)函數(shù)置入到引擎環(huán)境中
第四行調(diào)用hello方法,傳入?yún)?shù)World,并且將返回值強(qiáng)制為String類型
3、變量
在引擎中設(shè)置一個(gè)變量有兩種,第一是從java語言調(diào)用engine的put方法
engin.put("name","zhangsan")
第二種是在腳本里面var一個(gè)變量,再在engine里面進(jìn)行配置
engin.eval("var name=lisi;");
在和Java打交道的時(shí)候,更多從Java方面獲取對象參數(shù),然后到JS里面去運(yùn)算;所以在JAVA里面把變量準(zhǔn)備好,包括入?yún)⒑统鰠⒍歼M(jìn)行設(shè)定,然后在JS使用這些變量,當(dāng)然也可以傳入?yún)?shù),輸出復(fù)雜對象最好是設(shè)定一個(gè)變量。舉個(gè)例子:
//對上面的方法進(jìn)行擴(kuò)展
Map<String, Object> map = new HashMap<String, Object>();//一個(gè)哈希表
map.put("a", "abc");//向哈希表增加一個(gè)元素
engine.put("map", map);//把這個(gè)哈希表丟到JS引擎中去
//執(zhí)行一段JS腳本,作用是把一個(gè)鍵值對為currentTime和當(dāng)前時(shí)間丟到哈希表
engine.eval("map.put('currentTime','20161022');");
Student student=new Student();//這是一個(gè)普通的POJO
student.setAge(12);
student.setName("張三");
engine.put("student", student);
String script = "function hello(name) { return 'Hello,' + map.get('currentTime')+map.get('a')+student.getName();}";
engine.eval(script);
Invocable inv = (Invocable) engine;
String res = (String) inv.invokeFunction("hello", "World");
System.out.println(res);
4、JS里面使用JDK
在JS腳本里面使用JDK的方法需要增加Packages后面包名、類和類的方法
String js = "function getUUID(){var f=Packages.java.util.UUID.randomUUID();print(f)}";
engine.eval(js);
Invocable inv = (Invocable) engine;
inv.invokeFunction("getUUID");
很多時(shí)候,JS的功能不如Java強(qiáng)大,而這種JS中使用JAVA方法顯得非常重要
5、JSON
JSON 作為對象的組織者介于JAva和JavaScript之間都能比較好的傳輸數(shù)據(jù)、組裝數(shù)據(jù),我們使用第三方JSON處理包來做一個(gè)例子
String jsonStr="{'key':'value','SubSets':[{'x':'abc'},{'y':'edf'}],'random':Math.random()},{'other':'info'}";
JSONObject json=new JSONObject(jsonStr);
// engine.put("json", json);
String script = "function hello(json) { return 'Hello,'
+ json.getJSONArray(\"SubSets\").getJSONObject(0).get(\"x\").toString();}";
engine.eval(script);
Invocable inv = (Invocable) engine;
String res = (String) inv.invokeFunction("hello", json);
System.out.println(res);
首先是一個(gè)比較復(fù)雜的JSON對象,使用org.json.JSONObject進(jìn)行封裝,作為入?yún)鬟f進(jìn)入JS引擎的hello方法,該方法對JSON對象進(jìn)行解析也是利用org.json.JSONObject的方法。
6、實(shí)現(xiàn)Java接口
JS實(shí)現(xiàn)java的接口,來完成具體業(yè)務(wù)
String script = "var obj = new Object();obj.run = function() { println('執(zhí)行具體方法==='+name);}";
engine.put("name", "全局參數(shù)");
engine.eval(script);
Object obj = engine.get("obj");
Invocable inv = (Invocable) engine;
Runnable r = inv.getInterface(obj, Runnable.class);
Thread th = new Thread(r);
th.start();
此處使用Runnable接口開啟一個(gè)新的線程,具體的業(yè)務(wù)邏輯封裝在JS里面,業(yè)務(wù)需要返回值可以自定義一個(gè)接口,比如
public ReturnObj execute();,那么JS里面的obj.execute方法就是具體干活的地方。
7、其他
JS里面手動清除一個(gè)變量,或者對象使用delete方法
var a=10;
a;//出現(xiàn)10
delete(a);
a;//出現(xiàn)Uncaught ReferenceError: a is not defined