FreeMarker 自定义指令,并增加参数(四)

1. 模板文件 test05.ftl

<#assign x = 1>

<@repeat count=4>
  Test ${x}
  <#assign x++>
@repeat>

<@repeat count=3 hr=true>
  Test
@repeat>

<@repeat count=3; loopv>
  ${loopv}. Test
@repeat>

2. 自定义指令类(带参数)RepeatDirective.java

package com.freemarker.test05.Directives2;

import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;

import freemarker.core.Environment;
import freemarker.template.SimpleNumber;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateNumberModel;

/**
 * FreeMarker 用户自定义指令来重复模板中的一部分,可选的是使用 <hr>来分隔输出内容中的重复部分。
 * 

指令内容

*

参数: *

    *
  • count: 重复的次数。必须! * 必须是一个非负的数字,如果它不是一个整数,那么小数部分就会被。 * 舍去. *
  • hr: 用来辨别 HTML 的 "hr"元素是否在重复内容之 * 间被打印出来。布尔值。 可选, 默认是false。 *
*

循环变量: 1, 可选的。它给定了当前重复内容的数量,从 1 开始。 *

嵌套内容: 是 */ public class RepeatDirective implements TemplateDirectiveModel { private static final String PARAM_NAME_COUNT = "count"; private static final String PARAM_NAME_HR = "hr"; public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // --------------------------------------------------------------------- // 处理参数: int countParam = 0; boolean countParamSet = false; boolean hrParam = false; Iterator paramIter = params.entrySet().iterator(); while (paramIter.hasNext()) { Map.Entry ent = (Map.Entry) paramIter.next(); String paramName = (String) ent.getKey(); TemplateModel paramValue = (TemplateModel) ent.getValue(); if (paramName.equals(PARAM_NAME_COUNT)) { if (!(paramValue instanceof TemplateNumberModel)) { throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "must be a number."); } countParam = ((TemplateNumberModel) paramValue).getAsNumber() .intValue(); countParamSet = true; if (countParam < 0) { throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "can't be negative."); } } else if (paramName.equals(PARAM_NAME_HR)) { if (!(paramValue instanceof TemplateBooleanModel)) { throw new TemplateModelException("The \"" + PARAM_NAME_HR + "\" parameter " + "must be a boolean."); } hrParam = ((TemplateBooleanModel) paramValue).getAsBoolean(); } else { throw new TemplateModelException("Unsupported parameter: " + paramName); } } if (!countParamSet) { throw new TemplateModelException("The required \"" + PARAM_NAME_COUNT + "\" paramter" + "is missing."); } if (loopVars.length > 1) { throw new TemplateModelException( "At most one loop variable is allowed."); } // 是啊, 它很长而且很无聊... // 执行真正指令的执行部分: Writer out = env.getOut(); if (body != null) { for (int i = 0; i < countParam; i++) { // 如果"hr"参数为 true ,那么就在所有重复部分之间打印


:
if (hrParam && i != 0) { out.write("
"
); } // 如果有循环变量,那么就设置它: if (loopVars.length > 0) { loopVars[0] = new SimpleNumber(i + 1); } // 执行嵌入体部分(和 FTL 中的<#nested>一样)。 // 这种情况下,我们不提供一个特殊的 writer 作为参数: body.render(env.getOut()); } } } }

3. 测试类 Test.java

package com.freemarker.test05.Directives2;

import freemarker.template.*;
import java.util.*;
import java.io.*;

public class Test {

    public static void main(String[] args) throws Exception {

        // 创建 Freemarker 配置实例
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        // 指定模板文件从何处加载的数据源,这里设置成一个文件目录。
        cfg.setDirectoryForTemplateLoading(new File("templates"));
        cfg.setDefaultEncoding("UTF-8");
        // 简单地重新抛出异常; 这应该在大多数生产系统中使用。
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

        // 创建一个数据模型
        Map root = new HashMap();
        // 测试自定义指令 --------------------------------
        root.put("repeat", new RepeatDirective());

        // 获取模板(使用内部缓存)
        Template temp = cfg.getTemplate("test05.ftl");

        // 合并数据模型模板
        Writer out = new OutputStreamWriter(System.out);
        temp.process(root, out);
        out.flush();
        out.close();
        // 注意: ------------
        // 为了简单起见,这里压制了异常(在方法签名中声明了异常,译者注),而在正式运行的产品中不要这样做。
    }
}

运行结果


  Test 1
  Test 2
  Test 3
  Test 4

  Test
<hr>  Test
<hr>  Test

  1. Test
  2. Test
  3. Test

你可能感兴趣的:(freemarker)