1.24 直接运行Beetl脚本
About 1357 wordsAbout 5 min
2021-03-27
1.24 直接运行Beetl脚本
Beetl除了能被用来做模板引擎外,也可以做脚本引擎,规则引擎。Beetl模板本质上会转化为Beetl脚本来执行,这点跟jsp转为servlet来执行类似。BeetlSQL支持3种运行脚本方式
1.24.1 javax.script.ScriptManager 集成
Beetl集成了javax.script.ScriptManager,可以更为方便的使用脚本语言
//初始化部分,beetlEngine应该做为单例使用
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine beetlEngine = scriptEngineManager.getEngineByName("beetl");
//一个简单例子
SimpleBindings simpleBindings = new SimpleBindings();
simpleBindings.put("arg",arg);
Map map = null;
try {
map = (Map)beetlEngine.eval("return arg.age+(arg.pay+12);",simpleBindings);
return map.get("return");
} catch (ScriptException e) {
System.out.println(e);
}
执行脚本完毕后,返回到Map里的值可能包含如下:
- 模板的顶级的临时变量,key为临时变量名,value为值
- return 将返回到map里 ,key为"return"
异常e是ScriptException的子类BeetlScriptException,异常信息包含了具体的异常,异常位置。
- 如果是想校验脚本语法,需要参考1.24.2 使用Beetl内置的validate方法
- 如果想在线Debug脚本,类似 http://ibeetl.com/beetlonline/script.html ,需要参考1.24.4
1.24.2 Scriipt对象 直接调用
在上面的例子,BeetlScriptEngine是ScriptEngine的子类,他实际执行了Beetl的内置的Script功能。,可以掉用getScript方法获取Script对象
StringTemplateResourceLoader loader = new StringTemplateResourceLoader();
GroupTemplate gt = getGroupTemplate(); //假设从某处获GroupTemplate
String str = "var a=1+b;return a;"
Script script = gt.getScript(str,loader); //必须使用StringTemplateResourceLoader记载字符串脚本
Map map = new HashMap();
map.put("b",2);
script.binding(map);
script.execute();
if(script.isSuccess()){
return script.getResult(); //返回Map,包含了变量a,以及变量"return"
}
ErrorInfo error = script.getErrorInfo();
System.out.println(error) //打印出错详情
注意:这种方式性能比集成ScriptManager稍微好些。
也可以获取Script对象后,调用validate方法验证模板本生是否语法合格
String str = "var a=1+b;return a;"
Script script = gt.getScript(str,loader);
BeetlExeception ex = script.validate();
if(ex!=null){
ErrorInfo error = new ErrorInfo(ex) //转化成更好处理的ErrorInfo对象
System.out.println(error) //打印出错详情
}
对于集成ScriptEngine的例子,你可以获得Script对象做校验
BeetlScriptEngine beetlEngine = (BeetlScriptEngine)scriptEngineManager.getEngineByName("beetl");
Script script = beetlEngine.getScript(strScript);
//其他代码同上
1.24.3 GroupTemplate直接调用
GroupTemplate提供方法可以直接执行Beetl脚本,直接得出结果(不推荐了)
- public Map runScript(String key, Map<String, Object> paras) throws ScriptEvalError
- public Map runScript(String key, Map<String, Object> paras, Writer w) throws ScriptEvalError
- public Map runScript(String key, Map<String, Object> paras, Writer w, ResourceLoader loader) throws ScriptEvalError
key为资源名,这里是脚本字符串,paras为脚本的全局变量,w可选参数,如果执行脚本有输出,则输出到w里,loader参数可选,如果指定,则使用此laoder加载脚本
执行脚本完毕后,返回到Map里的值可能包含如下:
- 模板的顶级的临时变量,key为临时变量名,value为值
- return 值将返回到map里 ,key为return
如下脚本(此时就不需要脚本定界符了)
var a = 1;
var b = date();
var c = '2';
return a+1;
调用runScript后,map里将返回key分别为a,b,c,return。 值分别为1,当前日期,字符串'2,以及3。
groupTemplate.validateScript 可以用于校验模板是否正确,如果不正确,返回BeetlException
BeetlException ex = groupTemplate.validateScript(script);
if(ex!=null){
ErrorInfo info = new ErrorInfo(ex);
System.out.println(info.toString());
}
1.24.4 在线Debug
当Beetl作为脚本引擎时候,有时候需要支持在线Debug功能,比如为物联网的规则引擎,编写脚本时候可能需要调试脚本运行是否正确,比如流程引擎编写规则的时候,或者模拟运行的时候,也需要Debug脚本
通过Debug Beetl脚本,可以知道Beetl任何一行代码运行的上下文变量。类似http://ibeetl.com/beetlonline/script.html
为了让Beetl支持Debug功能,需要对GroupTemplate做一些设置,可以参考源码online模块的OnlineDebugController
GroupTemplate debugGroupTemplate;
protected void init() throws IOException {
Configuration conf = Configuration.defaultConfiguration();
debugGroupTemplate = new GroupTemplate(conf);
//Debug
debugGroupTemplate.setEngine(new org.beetl.core.debug.OnlineDebugTemplateEngine());
debugGroupTemplate.setErrorHandler(new ReThrowConsoleErrorHandler());
debugGroupTemplate.setNativeSecurity(new WhiteListNativeSecurityManager());
}
如上代码,类似Beetl在线引擎,但做了一些额外设定,如果你不关心Debug原理,则不需要参考下面内容。参考online模块完成你的在线引擎Debug功能。
如果想知道Beetl如何实现在线Debug,可以了解OnlineDebugTemplateEngine,如下
- OnlineDebugTemplateEngine引擎会在解析Beetl脚本时候,在换行地方增加了一个新的AST节点
WrapDebugHoldonStatement
,这个AST会在执行的时候休眠,等待进一步指示 - OnlineDebugTemplateEngine生成的AST的Program是
DebugProgram
,为Program子类,此类执行的上下文从Context变成DebugContext
,这是在线Debug非常重要的类,几乎所有的功能都conf这里开始。此类能输出程序运行到某行的所有变量,普通Context则没有这个功能 - DebugContext还具备设备断点,恢复运行等功能
文档2.15 定制模板引擎 包含了更多如何定制Beetl模板引擎功能
如下是使用DebugContext的大概介绍,来自代码OnlineDebugController
Script script = debugGroupTemplate.getScript(input,loader);
BeetlException exception = script.validate();
if(exception!=null){
ErrorInfo errorInfo = new ErrorInfo(exception);
return getConsole("脚本校验出错:"+errorInfo.getMsg()+" @line "+errorInfo.getErrorTokenLine());
}
DebugContext debugContext = (DebugContext)script.getContext();
//默认单行调试开始
debugContext.setDebugStatus(0);
Map debugInfo = new HashMap();
debugInfo.put("line",-1);
debugInfo.put("vars", null);
request.getSession(true).setAttribute("debugInfo",debugInfo);
debugContext.setDebugLockListener(new DebugLockListener() {
@Override
public void notifyHoldon(DebugContext debugContext,int line) {
//执行到断点
debugInfo.put("line",line);
debugInfo.put("vars",debugContext.currentVars(line));
System.out.println("wait on line "+line+" vars "+debugContext.currentVars(line));;
}
});
最主要的是调用setDebugLockListener
,当BeetlEngine执行到新的一行的时候,会调用此方法。