`

freemarker中实现自定义标签(包含处理参数以及循环变量)(2.3.11版本以后的方式)

阅读更多

 

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 自定义标签实现重复输出内容体。
 * 
 * 
 * 参数:
 * count: 重复的次数,必须的且非负整数。
 * hr: 设置是否输出HTML标签 "hr" 元素. Boolean. 可选的默认为fals.
 * 
 * 
 * 循环变量: 只有一个,可选的. 从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.");
		}

		// Yeah, it was long and boring...

		// ---------------------------------------------------------------------
		// 真正开始处理输出内容

		Writer out = env.getOut();
		if (body != null) {
			for (int i = 0; i < countParam; i++) {
				// 输出  <hr> 如果 参数hr 设置为true
				if (hrParam && i != 0) {
					out.write("<hr>");
				}

				// 设置循环变量
				if (loopVars.length > 0) {
					loopVars[0] = new SimpleNumber(i + 1);
				}

				// 执行标签内容(same as <#nested> in FTL). 
				body.render(env.getOut());
			}
		}
	}

}

 

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

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * 
 * 模板工具类
 */
public class FreeMarkertUtil {
	/**
	 * @param templatePath 模板文件存放目录 
	 * @param templateName 模板文件名称 
	 * @param root 数据模型根对象
	 * @param templateEncoding 模板文件的编码方式
	 * @param out 输出流
	 */
	public static void processTemplate(String templatePath, String templateName, String templateEncoding, Map<?,?> root, Writer out){
		try {
			Configuration config=new Configuration();
			File file=new File(templatePath);
			//设置要解析的模板所在的目录,并加载模板文件
			config.setDirectoryForTemplateLoading(file);
			//设置包装器,并将对象包装为数据模型
			config.setObjectWrapper(new DefaultObjectWrapper());
			
			//获取模板,并设置编码方式,这个编码必须要与页面中的编码格式一致
			Template template=config.getTemplate(templateName,templateEncoding);
			//合并数据模型与模板
			
		    template.process(root, out);
		    out.flush();
		    out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}catch (TemplateException e) {
			e.printStackTrace();
		}
		
	} 
}

 

 

import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * 客户端测试模板输入类
 */
public class RepeatTest {
	public static void main(String[] args) {
		Map<String,Object> root=new HashMap<String, Object>();

		root.put("repeat", new RepeatDirective());
		
		FreeMarkertUtil.processTemplate("src/templates","repeat.ftl", "UTF-8", root, new OutputStreamWriter(System.out));
		
	}
}

 

 模板文件repeat.ftl如下:

 

<#assign x = 1>

一个参数:
<@repeat count=4>
  Test ${x}
  <#assign x = x + 1>
</@repeat>

二个参数:
<@repeat count=3 hr=true>
  Test
</@repeat>

循环变量:
<@repeat count=3; cnt>
  ${cnt}. Test
</@repeat>  

 

 输出结果:

一个参数:
  Test 1
  Test 2
  Test 3
  Test 4

二个参数:
  Test
<hr>  Test
<hr>  Test

循环变量:
  1. Test
  2. Test
  3. Test

 

分享到:
评论
2 楼 qiuq86 2013-04-08  
你好,请教一下,这个自定义标签的话,每次调用需要在类里添加FreeMarkertUtil.processTemplate("src/templates","repeat.ftl", "UTF-8", root, new OutputStreamWriter(System.out));来指定需要处理哪一个ftl吗,如果是这样的话,那么自定义标签不是不能通用了?
1 楼 mengfei86 2011-12-07  
 

相关推荐

Global site tag (gtag.js) - Google Analytics