今天在 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") 极其方便