Java中原生解析JavaScript指令碼語言
阿新 • • 發佈:2018-12-14
前言
由於一些需求,現在需要在Java中解析字串,做一些簡單的算數運算和邏輯運算,那麼最先想的是模板引擎這個東西,但是Java中的模板引擎是針對View層的,也就是JSP的,在Service層中使用不是太方便,因此選用了原生的JavaScript指令碼解析引擎。實際上Java原生支援解析大部分指令碼語言,像JavaScript,PHP,Python等。
那麼,先貼一下核心實現類的程式碼:
import java.io.FileNotFoundException; import java.util.Map; import javax.script.ScriptException; public interface TempletEngineService { public Object eval(String script) throws ScriptException, FileNotFoundException; public Object eval(String script, Map<String, Object> vars) throws ScriptException, FileNotFoundException; }
然後是實現類:
import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @Service public class TempletEngineServiceImpl implements TempletEngineService { private ScriptEngine jsEngine; public TempletEngineServiceImpl() { ScriptEngineManager manager = new ScriptEngineManager(); jsEngine = manager.getEngineByName("JavaScript"); } @Override public Object eval(String script) throws ScriptException, FileNotFoundException { if (script == null || script.equals("")) { return null; } String jsfile = "/home/phw/Workspaces/MyEclipseProjects/gomoo-fu/src/com/gomoo/util/script/template.js"; jsEngine.eval(new FileReader(new File(jsfile))); return jsEngine.eval(script); } @Override public Object eval(String script, Map<String, Object> vars) throws ScriptException, FileNotFoundException { if (script == null || script.equals("")) { return null; } if (vars == null || vars.isEmpty()) { for (Map.Entry<String, Object> entry: vars.entrySet()) { jsEngine.put(entry.getKey(), entry.getValue()); } } return eval(script); } }
主要的核心類就是這兩個檔案,可以看到,用到的解析引擎是javax.script包下的引擎。
指令碼是自定義的一串符合JavaScript規則的字串,像簡單點的字串“5 + 6”、"9 - (6 + 5) * 5"等等,可以直接執行eval函式;若需要計算一些複雜的邏輯,那可以寫到你自定義的一個js檔案裡,然後在指令碼中執行那個函式;那再複雜一點,在函式中或者指令碼中帶自定義引數,這時就用到了eval(String script, Map vars)函數了。
下面是一些例子:
/** * 簡單字串的測試 * @throws ScriptException * @throws FileNotFoundException */ @Test public void testEval() throws FileNotFoundException, ScriptException { String script = "(65 - 5) / (3 * 6)"; String script2 = "15 > 10 ? 15 : 10"; String script3 = "15 > 10"; Object val1 = templetEngineService.eval(script); System.out.println("指令碼1的結果為:" + val1); Object val2 = templetEngineService.eval(script2); System.out.println("指令碼2的結果為:" + val2); Object val3 = templetEngineService.eval(script3); System.out.println("指令碼3的結果為:" + val3); } /** * 指令碼1的結果為:3.3333333333333335 * 指令碼2的結果為:15 * 指令碼3的結果為:true */ /** * 帶函式的指令碼測試 * @throws ScriptException * @throws FileNotFoundException */ @Test public void testEval2() throws FileNotFoundException, ScriptException { String script = "random()"; String script2 = "random() + random()"; Object val1 = templetEngineService.eval(script); System.out.println("指令碼1的結果為:" + val1); Object val2 = templetEngineService.eval(script2); System.out.println("指令碼2的結果為:" + val2); } /** * 指令碼1的結果為:63.0 * 指令碼2的結果為:163.0 */ /** * 帶引數的指令碼測試 * @throws FileNotFoundException * @throws ScriptException */ @Test public void testEval3() throws FileNotFoundException, ScriptException { String script = "random(min, max)"; String script2 = "random(min, max) + min - max"; Map<String, Object> vars = new HashMap<>(); vars.put("min", 10); vars.put("max", 100); Object val1 = templetEngineService.eval(script, vars); System.out.println("指令碼1的結果為:" + val1); Map<String, Object> vars2 = new HashMap<>(); vars.put("min", 100); vars.put("max", 1000); Object val2 = templetEngineService.eval(script2, vars2); System.out.println("指令碼2的結果為:" + val2); } /** * 指令碼1的結果為:69.0 * 指令碼2的結果為:-65.0 */ /** * 引數為類時的指令碼測試 * @throws FileNotFoundException * @throws ScriptException */ @Test public void testEval4() throws FileNotFoundException, ScriptException { User user = new User(); user.setRealName("phw"); String script = "out(user)"; Map<String, Object> vars = new HashMap<>(); vars.put("user", user); Object val = templetEngineService.eval(script, vars); System.out.println("指令碼1的結果為:" + val); } /** * 指令碼1的期望結果:phw */
下面貼一下template.js,也就是我們預定義的Js function的檔案:
/**
* 生成100內的隨機數
*/
function random() {
return Math.floor(Math.random() * 100);
}
/**
* 生成區間內的隨機整數[m, n]
*/
function random(minNum,maxNum){
switch(arguments.length){
case 1:
return parseInt(Math.random()*minNum+1,10);
break;
case 2:
return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
break;
default:
return 0;
break;
}
}
function out(obj) {
return obj.realName;
}
以上就是測試裡用到的js function函式,再說一下,指令碼不支援es6的語法,所以老老實實用var,不要用let。
以上。