FreeMarker 2.3.11版本以后提供了新的自定义标签接口TemplateDirectiveModel 以替代TemplateTransformModel,
下面是一个转换自定义标签的内容体中字母为大写字母的例子:
1 import java.io.IOException; 2 import java.io.Writer; 3 import java.util.Map; 4 5 import freemarker.core.Environment; 6 import freemarker.template.TemplateDirectiveBody; 7 import freemarker.template.TemplateDirectiveModel; 8 import freemarker.template.TemplateException; 9 import freemarker.template.TemplateModel; 10 import freemarker.template.TemplateModelException; 11 12 /** 13 * FreeMarker 自定义指令,用于转换指令内容体中的字母为大写字母。 14 * 15 */ 16 public class UpperDirective implements TemplateDirectiveModel { 17 18 public void execute(Environment env, Map params, TemplateModel[] loopVars, 19 TemplateDirectiveBody body) throws TemplateException, IOException { 20 // 检查是否传递参数,此指令禁止传参! 21 if (!params.isEmpty()) { 22 throw new TemplateModelException( 23 "This directive doesn't allow parameters."); 24 } 25 // 禁用循环变量 26 /* 27 * 循环变量 28 用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在${"<@…>"}开始标记的参数后面指定循环变量的名字 29 例子: 30 <#macro repeat count> 31 <#list 1..count as x> 32 <#nested x, x/2, x==count> 33 </#list> 34 </#macro> 35 <@repeat count=4 ; c, halfc, last> 36 ${c}. ${halfc}<#if last> Last!</#if> 37 </@repeat> 38 */ 39 if (loopVars.length != 0) { 40 throw new TemplateModelException( 41 "This directive doesn't allow loop variables."); 42 } 43 44 // 指令内容体不为空 45 if (body != null) { 46 // Executes the nested body. Same as <#nested> in FTL, except 47 // that we use our own writer instead of the current output writer. 48 body.render(new UpperCaseFilterWriter(env.getOut())); 49 } else { 50 throw new RuntimeException("missing body"); 51 } 52 } 53 54 /** 55 * 输出流的包装器(转换大写字母) 56 */ 57 private static class UpperCaseFilterWriter extends Writer { 58 59 private final Writer out; 60 61 UpperCaseFilterWriter(Writer out) { 62 this.out = out; 63 } 64 65 public void write(char[] cbuf, int off, int len) throws IOException { 66 char[] transformedCbuf = new char[len]; 67 for (int i = 0; i < len; i++) { 68 transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]); 69 } 70 out.write(transformedCbuf); 71 } 72 73 public void flush() throws IOException { 74 out.flush(); 75 } 76 77 public void close() throws IOException { 78 out.close(); 79 } 80 } 81 82 }
1 import java.io.File; 2 import java.io.IOException; 3 import java.io.Writer; 4 import java.util.Map; 5 6 import freemarker.template.Configuration; 7 import freemarker.template.DefaultObjectWrapper; 8 import freemarker.template.Template; 9 import freemarker.template.TemplateException; 10 11 /** 12 * 13 * 模板工具类 14 */ 15 public class FreeMarkertUtil { 16 /** 17 * @param templatePath 模板文件存放目录 18 * @param templateName 模板文件名称 19 * @param root 数据模型根对象 20 * @param templateEncoding 模板文件的编码方式 21 * @param out 输出流 22 */ 23 public static void processTemplate(String templatePath, String templateName, String templateEncoding, Map<?,?> root, Writer out){ 24 try { 25 Configuration config=new Configuration(); 26 File file=new File(templatePath); 27 //设置要解析的模板所在的目录,并加载模板文件 28 config.setDirectoryForTemplateLoading(file); 29 //设置包装器,并将对象包装为数据模型 30 config.setObjectWrapper(new DefaultObjectWrapper()); 31 32 //获取模板,并设置编码方式,这个编码必须要与页面中的编码格式一致 33 Template template=config.getTemplate(templateName,templateEncoding); 34 //合并数据模型与模板 35 36 template.process(root, out); 37 out.flush(); 38 out.close(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 }catch (TemplateException e) { 42 e.printStackTrace(); 43 } 44 45 } 46 }
1 import java.io.OutputStreamWriter; 2 import java.util.HashMap; 3 import java.util.Map; 4 5 /** 6 * 7 * 客户端测试模板输入类 8 */ 9 public class ClientTest { 10 public static void main(String[] args) { 11 Map<String,Object> root=new HashMap<String, Object>(); 12 13 root.put("upper", new UpperDirective()); 14 15 FreeMarkertUtil.processTemplate("src/templates","demo01.ftl", "UTF-8", root, new OutputStreamWriter(System.out)); 16 17 } 18 }
模板文件demo01.ftl如下:
1 <@upper> 2 bar 3 <#-- All kind of FTL is allowed here --> 4 <#list ["red", "green", "blue"] as color> 5 ${color} 6 </#list> 7 baaz 8 </@upper>