定制模板引擎
Beetl在线体验(http://ibeetl.com/beetlonline/)面临一个挑战,允许用户输入任何脚本做练习或者分享代码。但又需要防止用户输入恶意的代码,如
<%
while(true){
//其他代码
}
%>
此时,需要定制模板引擎,遇到while循环的时候,应该限制循环次数,譬如,在线体验限制最多循环5次,这是通过定义扩展模板引擎来实现的,以jar包自带的实例代码OnlineTemplateEngine来说明
public class OnlineTemplateEngine extends DefaultTemplateEngine {
public static int MAX = 5;
public static String ERROR = "错误:在线引擎不允许循环次数超过 " + MAX;
@Override
protected GrammarCreator getGrammerCreator(GroupTemplate gt) {
GrammarCreator grammar = new OnlineGrammarCreator();
return grammar;
}
}
扩展DefaultTemplateEngine,重载getGrammerCreator方法,返回一个我们自己的语法定义类OnlineGrammarCreator
OnlineGrammarCreator继承了默认的
static class OnlineGrammarCreator extends GrammarCreator {
@Override
public WhileStatement createWhile(Expression exp, Statement whileBody, GrammarToken token) {
WhileStatement whileStat = new RestrictWhileStatement(exp, whileBody, token);
return whileStat;
}
}
需要对for循环重新定义,使用新的 RestrictWhileStatement,定义如下
static class RestrictWhileStatement extends WhileStatement {
public RestrictWhileStatement(Expression exp, Statement whileBody, GrammarToken token) {
super(exp, whileBody, token);
}
@Override
public void execute(Context ctx) {
int i = 0;
while (i < OnlineTemplateEngine.MAX) {
Object result = exp.evaluate(ctx);
if (result instanceof Boolean) {
if ((Boolean) result) {
whileBody.execute(ctx);
} else {
break;
}
} else {
BeetlException be = new BeetlException(BeetlException.BOOLEAN_EXPECTED_ERROR);
be.token = exp.token;
throw be;
}
i++;
}
if (i >= OnlineTemplateEngine.MAX) {
try {
ctx.byteWriter.writeString(ERROR);
} catch (IOException e) {
// ignore
}
}
}
}
完成这些代码后,在配置文件中申明使用新的引擎
ENGINE=org.beetl.core.engine.OnlineTemplateEngine
这样就完成了模板引擎定制。
BeetlSQL 正是支持定制,所以才把## 占位符输出"?",而不是字面值,${} 负责输出字面值,可以查看BeetlSQL的org.beetl.sql.core.engine.SQLTemplateEngine