Freemark 应用指南
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML 网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个 Java 类库,是一款程序员可以嵌入他们所开发产品的组件。
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML 网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个 Java 类库,是一款程序员可以嵌入他们所开发产品的组件。
简言之:模板 + 数据 = 输出

img
首先,你应该创建一个
freemarker.template.Configuration
实例, 然后调整它的设置。Configuration 实例是存储 FreeMarker 应用级设置的核心部分。同时,它也处理创建和缓存预解析模板(比如 Template 对象)的工作。// Create your Configuration instance, and specify if up to what FreeMarker
// version (here 2.3.22) do you want to apply the fixes that are not 100%
// backward-compatible. See the Configuration JavaDoc for details.
Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
// Specify the source where the template files come from. Here I set a
// plain directory for it, but non-file-system sources are possible too:
cfg.setDirectoryForTemplateLoading(new File("/where/you/store/templates"));
// Set the preferred charset template files are stored in. UTF-8 is
// a good choice in most applications:
cfg.setDefaultEncoding("UTF-8");
// Sets how errors will appear.
// During web page *development* TemplateExceptionHandler.HTML_DEBUG_HANDLER is better.
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
注:不需要重复创建 Configuration 实例;它的代价很高,尤其是会丢失缓存。Configuration 实例就是应用级别的单例。
在简单的示例中你可以使用
java.lang
和 java.util
包中的类, 还有用户自定义的 Java Bean 来构建数据对象:- 使用
java.lang.String
来构建字符串。 - 使用
java.lang.Number
来派生数字类型。 - 使用
java.lang.Boolean
来构建布尔值。 - 使用
java.util.List
或 Java 数组来构建序列。 - 使用
java.util.Map
来构建哈希表。 - 使用自定义的 bean 类来构建哈希表,bean 中的项和 bean 的属性对应。比如,
product
的price
属性 (getProperty()
)可以通过product.price
获取。(bean 的 action 也可以通过这种方式拿到; 要了解更多可以参看 这里)
示例:
// Create the root hash
Map<String, Object> root = new HashMap<>();
// Put string ``user'' into the root
root.put("user", "Big Joe");
// Create the hash for ``latestProduct''
Map<String, Object> latest = new HashMap<>();
// and put it into the root
root.put("latestProduct", latest);
// put ``url'' and ``name'' into latest
latest.put("url", "products/greenmouse.html");
latest.put("name", "green mouse");
Template temp = cfg.getTemplate("test.ftl");
当调用这个方法的时候,将会创建一个
test.ftl
的 Template
实例,通过读取 */where/you/store/templates/*test.ftl
文件,之后解析(编译)它。Template
实例以解析后的形式存储模板, 而不是以源文件的文本形式。Configuration
缓存 Template
实例,当再次获得 test.ftl
的时候,它可能再读取和解析模板文件了, 而只是返回第一次的 Template
实例。我们已经知道,数据模型+模板=输出,我们有了一个数据模型 (
root
) 和一个模板 (temp
), 为了得到输出就需要合并它们。这是由模板的 process
方法完成的。它用数据模型 root 和 Writer
对象作为参数,然后向 Writer
对象写入产生的内容。 为简单起见,这里我们只做标准的输出:Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
Java I/O 相关注意事项:基于
out
对象,必须保证 out.close()
最后被调用。当 out
对象被打开并将模板的输出写入文件时,这是很电影的做法。其它时候, 比如典型的 Web 应用程序,那就 不能 关闭 out
对象。FreeMarker 会在模板执行成功后 (也可以在 Configuration
中禁用) 调用 out.flush()
,所以 不必为此担心。请注意,一旦获得了
Template
实例, 就能将它和不同的数据模型进行不限次数 (Template
实例是无状态的)的合并。此外, 当 Template
实例创建之后 test.ftl
文件才能访问,而不是在调用处理方法时。注意观察每个数据模型的例子你也许能发现:被"(root)"所标识的内容就是哈希表类型的值。 当编写如
user
这样的代码时,那就意味着要把"user"变量存储在哈希表的根上。 就像编写 root.user
一样,这里但并没有名"root"为的变量, 那么这就起不到任何作用了。某些人也许会被这种数据模型的例子所困惑,也就是说,根哈希表包含更多的哈希表或序列 (
lotteryNumbers
and cargo
)。其它就没有更特殊的内容了。 哈希表包含其他变量,那些变量包含其它值,这些数值可以是字符串,数字等变量, 当然也可以是哈希表或序列变量。最初我们解释过的,就像字符串和数字, 序列或哈希表也是一种值的表示形式。Freemark 支持的类型有:
模板(FTL 编程)是由如 下部分混合而成的:
- 文本:文本会照着原样来输出。
- 插值:这部分的输出会被计算的值来替换。插值由
${
and}
所分隔。 - FTL 标签:FTL 标签和 HTML 标签很相似,但是它们却是给 FreeMarker 的指示, 而且不会打印在输出内容中。
- 注释:注释和 HTML 的注释也很相似,但它们是由
<#--
和-->
来分隔的。注释会被 FreeMarker 直接忽略, 更不会在输出内容中显示。

img
🔔 注意:
FTL 是区分大小写的。插值
仅仅可以在文本
中使用。FTL 标签
不可以在其他FTL 标签
和插值
中使用。注释
可以放在FTL 标签
和插值
中。
使用 FTL 标签来调用 指令。
FTL 标签分为两种:
- 开始标签:
<#*directivename* *parameters*>
- 结束标签:
</#*directivename*>
除了标签以
#
开头外,其他都和 HTML,XML 的语法很相似。 如果标签没有嵌套内容(在开始标签和结束标签之间的内容),那么可以只使用开始标签。 例如 <#if *something*>*...*</#if>
, 而 FreeMarker 知道 <#include *something*>
中的 include
指令没有可嵌套的内容。*parameters*
的格式由 *directivename*
来决定。🔔 注意:
FreeMarker 仅仅关心 FTL 标签的嵌套而不关心 HTML 标签的嵌套。 它只会把 HTML 看做是文本,不会来解释 HTML。 如果你尝试使用一个不存在的指令(比如,输错了指令的名称), FreeMarker 就会拒绝执行模板,同时抛出错误信息。