今天在 jfinal 俱乐部有同学碰到个需求,希望在调用模板函数时去除 html 标签前后的空格与换行,需要处理的模板函数定义如下:
#define test() <div> <span> 模块一 </span> </div> #end
以上模板函数的内容需要在 html 中嵌入的 javascript 代码中使用:
var str = "#@test()";
由于调用模板函数 #@test() 后生成的内容是有空格与换行的,javascript 部分最终生成的结果如下:
var str = "<div> <span> 模块一 </span> </div> ";
以上代码显然是不能工作的 js 片段。能正常工作的 js 代码片段是下面这样的:
var str = "<div><span>模块一</span></div>";
也就是说调用模板函数生成的内容需要去除其中的空格与换行。解决办法是通过扩展 CallDirective 实现一个自己的 MyCallDirecitve,代码如下:
import java.io.BufferedReader; import java.io.StringReader; import com.jfinal.template.Env; import com.jfinal.template.TemplateException; import com.jfinal.template.ext.directive.CallDirective; import com.jfinal.template.io.CharWriter; import com.jfinal.template.io.FastStringWriter; import com.jfinal.template.io.Writer; import com.jfinal.template.stat.Scope; import com.jfinal.template.stat.ast.Define; /** * 调用模板函数,并去除文本行前后空格与换行字符 */ public class MyCallDirective extends CallDirective { public void exec(Env env, Scope scope, Writer writer) { Object funcNameValue = funcNameExpr.eval(scope); if (funcNameValue == null) { if (nullSafe) { return ; } throw new TemplateException("模板函数名为 null", location); } if (!(funcNameValue instanceof String)) { throw new TemplateException("模板函数名必须是字符串", location); } Define func = env.getFunction(funcNameValue.toString()); if (func == null) { if (nullSafe) { return ; } throw new TemplateException("模板函数未找到 : " + funcNameValue, location); } // ------------------------------------------------------------- CharWriter charWriter = new CharWriter(64); FastStringWriter fsw = new FastStringWriter(); charWriter.init(fsw); try { func.call(env, scope, paraExpr, charWriter); } finally { charWriter.close(); } // ------------------------------------------------------------- String content = fsw.toString(); fsw.close(); try (BufferedReader br = new BufferedReader(new StringReader(content))) { String line; while ((line=br.readLine()) != null) { fsw.append(line.trim()); } write(writer, fsw.toString()); } catch (Exception e) { throw new TemplateException(e.getMessage(), location); } } }
代码主体是照抄 CallDirective,并在 exec 中做了少许改进,对每行内容进行了一个 trim() 操作,然后再输出到 Writer 中。
要使用上述 MyCallDirective 指令,需要如下配置:
engine.addDirective("myCall", MyCallDirective.class, false);
然后就可以在模板中使用了:
var str = "#myCall('test')";
最终生成的 js 片段如下:
var str = "<div><span>模块一</span></div>";
完美解决,打完收工。
通过使用上面的 MyCallDirective 指令,可以实现 html 模板内容压缩的功能,也就是去除 html 模板文本行前后的空白字符,可以节省 web 项目的网络流量,对于访问量巨大的大型 web 项目十分有益。
具体到现有的 jfinal 最佳实践项目中,只需将以往的模板函数调用改成 #myCall 形式即可,主要有如下几处:
### 在 index.html 这类模板文件中 #myCall("layout") ### 在 layout.html 中 #myCall("main")
极其方便