定制模板引擎

Beetl在线体验(http://ibeetl.com/beetlonline/)面临一个挑战,允许用户输入任何脚本做练习或者分享代码。但又需要防止用户输入恶意的代码,如

  1. <%
  2. while(true){
  3. //其他代码
  4. }
  5. %>

此时,需要定制模板引擎,遇到while循环的时候,应该限制循环次数,譬如,在线体验限制最多循环5次,这是通过定义扩展模板引擎来实现的,以jar包自带的实例代码OnlineTemplateEngine来说明

  1. public class OnlineTemplateEngine extends DefaultTemplateEngine {
  2. public static int MAX = 5;
  3. public static String ERROR = "错误:在线引擎不允许循环次数超过 " + MAX;
  4. @Override
  5. protected GrammarCreator getGrammerCreator(GroupTemplate gt) {
  6. GrammarCreator grammar = new OnlineGrammarCreator();
  7. return grammar;
  8. }
  9. }

扩展DefaultTemplateEngine,重载getGrammerCreator方法,返回一个我们自己的语法定义类OnlineGrammarCreator

OnlineGrammarCreator继承了默认的

  1. static class OnlineGrammarCreator extends GrammarCreator {
  2. @Override
  3. public WhileStatement createWhile(Expression exp, Statement whileBody, GrammarToken token) {
  4. WhileStatement whileStat = new RestrictWhileStatement(exp, whileBody, token);
  5. return whileStat;
  6. }
  7. }

需要对for循环重新定义,使用新的 RestrictWhileStatement,定义如下

  1. static class RestrictWhileStatement extends WhileStatement {
  2. public RestrictWhileStatement(Expression exp, Statement whileBody, GrammarToken token) {
  3. super(exp, whileBody, token);
  4. }
  5. @Override
  6. public void execute(Context ctx) {
  7. int i = 0;
  8. while (i < OnlineTemplateEngine.MAX) {
  9. Object result = exp.evaluate(ctx);
  10. if (result instanceof Boolean) {
  11. if ((Boolean) result) {
  12. whileBody.execute(ctx);
  13. } else {
  14. break;
  15. }
  16. } else {
  17. BeetlException be = new BeetlException(BeetlException.BOOLEAN_EXPECTED_ERROR);
  18. be.token = exp.token;
  19. throw be;
  20. }
  21. i++;
  22. }
  23. if (i >= OnlineTemplateEngine.MAX) {
  24. try {
  25. ctx.byteWriter.writeString(ERROR);
  26. } catch (IOException e) {
  27. // ignore
  28. }
  29. }
  30. }
  31. }

完成这些代码后,在配置文件中申明使用新的引擎

  1. ENGINE=org.beetl.core.engine.OnlineTemplateEngine

这样就完成了模板引擎定制。

BeetlSQL 正是支持定制,所以才把## 占位符输出"?",而不是字面值,${} 负责输出字面值,可以查看BeetlSQL的org.beetl.sql.core.engine.SQLTemplateEngine