大家都清楚,语言是需要执行环境的。js运行在前端浏览器,由js解释引擎,java运行在jvm中。最近在项目中遇到需要前端和后台都能执行的需求。在前端执行是为了节约服务器资源和提前验证脚本是否正确。在后端执行是用于定时作业。两边的脚本是同一个。即我要在不修改脚本的情况让脚本在JS和JAVA里面都能运行。
我选择的JavaScript,在前端执行很简单,问题是在服务器端,在网上找了找发现JDK自带了运行JS的环境。ScriptEngineManager这个类可以获取到JS的引擎。
现在的问题是怎么把JAVA对象传入到JS脚本中使用,虽然引擎提供了import功能。如下:engine.eval("importPackage(java.util)");这里有个矛盾就是前端不支持JAVA对象。所以我的脚本中不能出现JAVA对象,因为JAVA对象和获取值的方式和JS不一样。比如
在js中:var data={name:'rain',age:28};我要获取name可以通过data.name获取。
如果在java中Map<String,String> data=new HashMap<String,String>();data.put("name","rain");我也用data.name是会抛异常中。为了做到统一。所以我要做的全部使用JS支持的语法。把java对象转成JS对象。
转法很简单,先序列化JSON字符串传入engine,然后在engine中eval()把json字符串转成JS对象。这样就可以调用了。看代码吧。
先看看前端的JS代码效果:
<script> var params={name:'rain',age:'28'}; eval("var result=params.name;"); alert(result)//弹出的是rain </script>
在看看JAVA端没有转换时的结果:
@Test
public void test_params_error(){
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");// ScriptEngine用来处理脚本解释和求值
try{
Bindings bindings = engine.createBindings();
Map<String,String> params=new HashMap<String,String>();
params.put("name", "rain");
params.put("age", "28");
bindings.put("params", params);
engine.eval("var result=params.name;",bindings);
System.out.println(bindings.get("result"));//输出的是:sun.org.mozilla.javascript.internal.Undefined@4f1d0d
}catch(Exception e){
e.printStackTrace();
}
}
最后看看转换后的效果:
@Test
public void test_params_ok(){
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");// ScriptEngine用来处理脚本解释和求值
try{
Bindings bindings = engine.createBindings();
Map<String,String> params=new HashMap<String,String>();
params.put("name", "rain");
params.put("age", "28");
//序列化成json
bindings.put("paramsStr", SerializableTool.serialize(params));
engine.eval("var params=eval('('+paramsStr+')')",bindings);
engine.eval("var result=params.name;",bindings);
System.out.println(bindings.get("result"));//输出的是:rain
}catch(Exception e){
e.printStackTrace();
}
}
这样就实现的一段脚本,在前端和后台都能运行。