FreeMaker入门

 

第一章 简介

 

1 什么是FreeMaker

 

FreeMaker是一款模板引擎,即基于模板,用来生成文本的工具。可以用来实现MVC模式。FreeMaker基于BSD协议。是ISO认证的开源软件。

 

2. 简介

 

如果你的在线商店需要这样的页面如:

 

<html> 
<head> 
  <title>Welcome!</title> 
</head> 
<body> 
  <h1>Welcome tntxia!</h1> 
  <p>Our latest product: 
  <a href="products/greenmouse.html">green mouse</a>! 
</body> 
</html>

 

这里tntxia是用户名。应该使用动态。

 

FreeMaker是这样实现的。

 

<html> 
<head> 
  <title>Welcome!</title> 
</head> 
<body> 
  <h1>Welcome ${user}!</h1> 
  <p>Our latest product: 
  <a href="${latestProduct.url}">${latestProduct.name}</a>! 
</body> 
</html>   

 

FreeMaker可以使用Map、List对象,也可以自定义的数据模型。

 

${…}:FreeMaker会使用动态的数据改成$里面的内容。

 

FTL tags 标签(FreeMarker  模板的语言标签) :与HTML标签相似,一般以#开关,但也可以自定义。

 

Comments 注释:<#--    -->

 

 

 

 

 

 

可以增加一个Servlet:

 

package com.tntxia.freemaker.test;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class HelloFreeMarker extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6255189103129788283L;

	public HelloFreeMarker() {
		super();
	}

	// 负责管理FreeMarker模板的Configuration实例
	private Configuration cfg = null;

	public void init() throws ServletException {
		// 创建一个FreeMarker实例
		cfg = new Configuration();
		// 指定FreeMarker模板文件的位置
		cfg.setServletContextForTemplateLoading(getServletContext(),
				"/WEB-INF/templates");
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		// 建立数据模型
		Map root = new HashMap();
		root.put("message", "hello world");
		root.put("name", "聂靖宇");
		root.put("num", 5);
		
		DataModel data = new DataModel();
		root.put("data", data);
		
		// root.put("personList", list);

		// 获取模板文件
		Template t = cfg.getTemplate("test1.ftl");

		// 开始准备生成输出
		// - 使用模板文件的Charset作为本页面的charset
		// - 使用text/html MIME-type
		response.setContentType("text/html; charset=" + t.getEncoding());
		Writer out = response.getWriter();
		// 合并数据模型和模板,并将结果输出到out中
		try {
			t.process(root, out); // 往模板里写数据
		} catch (TemplateException e) {
			e.printStackTrace();
		}
	}

	public void destroy() {
		super.destroy();
	}
}

 

 在WEB-INF里面增加一个template的文件,增加一个FTL文件:

 

test1.ftl

 

<html>

  <head>      <title>Hello Word</title>     </head> 

   <body>        
<#--  测试注释                    -->
<h3>${message},${name}    ${data.test}</h3> 

<#if num > 5 >num  is 5</#if>
    </body> 

</html>

 


 

1.1 指令

 

1.1.1 if指令

 

<#if user == "Big Joe">, our beloved leader</#if>!

 

通过if指令,可以让符合条件的内容显示。

 

当condition 的判断结果为 false(布尔值)时,在<#if condition>和</#if>标签之间的内容将会被略过。

 

使用<#else>标签可以指定当条件为假时程序执行的内容。例如:

 

<#if animals.python.price < animals.elephant.price> 
  Pythons are cheaper than elephants today. 
<#else> 
  Pythons are not cheaper than elephants today. 
</#if>      

 

1.1.2 list指令

 

用List指令可以实现循环输出

 

如:

 

<p>We have these animals:
<table border=1>
  <tr><th>Name<th>Price
  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>
</table> 

 

  list 指令的一般格式为:
  <#list sequence as loopVariable>repeatThis</#list>
  repeatThis 部分将会在给定的sequence 遍历时在每项中重复,从第一项开始,
一个接着一个。在所有的重复中,loopVariable 将持有当前项的值。这个循环变量仅
存在于<#list …>和</#list>标签之间。

 

1.1.3  include指令

 

引入一个模板:

 

<#include "test.ftl">
 
使用

 

<#include "/test.ftl">
 
是一样的效果

 

文件的位置与模板文件夹一致。

 

1.1.4 不存在的变量的处理

 

${user!"Asynonymous"}

<#if user??>

welcome ${user}

<#else>

Asynonymous Again

</#if>

 

 FreeMaker容器:

 

2.2.3  容器
  这些值存在的目的是为了包含其他变量,它们仅仅作为容器。被包含的变量通常是子变
量。容器的类型有:
 哈希表:每个子变量都可以通过一个唯一的名称来查找,这个名称是不受限制的字
符串。哈希表并不确定其中子变量的顺序,也就是说没有第一个变量,第二个变量
这样的说法,变量仅仅是通过名称来访问的。 (就像 Java 语言中的 HashMap 一样,
是实现了 Hash 算法的 Map,不记录内部元素的顺序,仅仅通过名称来访问。译者
注)
  序列:每个子变量通过一个整数来标识。 第一个子变量的标识符是 0,第二个是 1,
第三个是 2,这样来类推,而且子变量是有顺序的。这些数字通常被称为是子变量
的索引。序列通常比较密集,也就是所有的索引,包括最后一个子变量的,它们和
子变量都是相关联的,但不是绝对必要的。 子变量的数值类型也并不需要完全一致。 
  集:  从模板设计者角度来看,集是有限制的序列。不能获取集的大小,也不能通过
索引取出集中的子变量,但是它们仍然可以通过 list 指令来遍历。

 

2.2.4 函数

 

The average of 3 and 5 is: ${avg(3, 5)} 
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)} 
The average of the price of a python and an elephant is: 
${avg(animals.python.price, animals.elephant.price)}  

 

输出结果:

 

The average of 3 and 5 is: 4 
The average of 6 and 10 and 20 is: 12 
The average of the price of a python and an elephant is: 
4999.5 

 

 

 2.2.5 自定义方法

 

方法变量在存于实现了 TemplateMethodModel 接口的模板中。这个接口仅包含方法调用表达式调用方法时, exec方法将会被调用。 形参将会包含FTL方法调用形参的值。exec 方法的返回值给出了 FTL 方法调用表达式的返回值。

 

2.2.6 自定义指令

 

  Java程序员可以使用TemplateDirectiveModel 接口在Java代码中实现自定义指令。详情可以参看 API 文档。

 

2.2.6.1  第一个示例

 

模板:

 

 

foo 
<@upper> 
  bar 
  <#-- 这里允许使用所有的 FTL --> 
  <#list ["red", "green", "blue"] as color> 
    ${color} 
  </#list> 
  baaz 
</@upper> 
wombat 
 

 

将会输出:

 

foo
  BAR
    RED
    GREEN
    BLUE
  BAAZ
wombat

 

下面是指令类的源代码:

root.put("upper", new com.example.UpperDirective()); 

 

 

package com.example; 
import java.io.IOException; 
import java.io.Writer; 
import java.util.Map; 
import freemarker.core.Environment; 
import freemarker.template.TemplateDirectiveBody; 
import freemarker.template.TemplateDirectiveModel; 
import freemarker.template.TemplateException; 
import freemarker.template.TemplateModel; 
import freemarker.template.TemplateModelException; 
/** 
 *  FreeMarker的用户自定义指令在逐步改变 
*  它嵌套内容的输出转换为大写形式 
*  <p><b>指令内容</b></p> 
*  <p>指令参数:无 
 *  <p>循环变量:无 
*  <p>指令嵌套内容:是 
*/ 
public class UpperDirective implements TemplateDirectiveModel 
{ 
   public void execute(Environment env, Map params, 
       TemplateModel[] loopVars, TemplateDirectiveBody body) 
       throws TemplateException, IOException { 
     // 检查参数是否传入 
     if (!params.isEmpty()) { 
         throw new TemplateModelException( 
                 "This directive doesn't allow parameters."); 
     } 
     if (loopVars.length != 0) { 
         throw new TemplateModelException("This directive 
                 doesn't allow loop variables."); 
     } 
     // 是否有非空的嵌入内容 
     if (body != null) { 
         // 执行嵌入体部分,和 FTL中的<#nested>一样,除了 
         // 我们使用我们自己的 writer 来代替当前的 output writer. 
         body.render(new UpperCaseFilterWriter(env.getOut())); 
        } else { 
            throw new RuntimeException("missing body"); 
        } 
} 
/** 
     * {@link Writer}改变字符流到大写形式, 
* 而且把它发送到另外一个{@link Writer}中。 
*/ 
private static class UpperCaseFilterWriter extends Writer { 
private final Writer out; 
UpperCaseFilterWriter (Writer out) { 
  this.out = out; 
} 
        public void write(char[] cbuf, int off, int len) 
            throws IOException { 
            char[] transformedCbuf = new char[len]; 
            for (int i = 0; i < len; i++) { 
                transformedCbuf[i] = Character. 
toUpperCase(cbuf[i + off]); 
            } 
            out.write(transformedCbuf); 
       } 
       public void flush() throws IOException { 
            out.flush(); 
       } 
       public void close() throws IOException { 
            out.close(); 
        } 
} 
}  
 

 

最后,把它放在数据模型里面,如:

 

 

root.put("upper", new com.example.UpperDirective()); 

 

第二个示例 :Repeat

 

 

 

 

 

你可能感兴趣的:(freemaker)