Java教程
  • Java教程
  • 简介
    • Java 库
      • JMH 应用指南
      • ZXing 应用指南
      • Thumbnailator 应用指南
      • Jsoup 应用指南
      • Dozer 应用指南
      • 细说 Java 主流日志工具库
      • Mockito 应用指南
      • JavaMail 应用指南
      • Freemark 应用指南
      • Lombok 应用指南
      • Java 与 JSON
      • JUnit5 应用指南
      • 细说 Java 主流工具包
      • Java 二进制序列化库
      • Reflections 应用指南
    • Java 工具
      • 构建工具
        • Ant 简易教程
        • Maven 教程
          • Maven 实战问题和最佳实践
          • Maven 教程之入门指南
          • Maven 插件之代码检查
          • Maven 教程之发布 jar 到私服或中央仓库
          • Maven 教程之 settings.xml 详解
          • Maven 教程之 pom.xml 详解
        • Gradle 应用指南
      • Elastic 技术栈
        • Elastic 技术栈之 Logstash 基础
        • Elastic 技术栈之 Kibana
        • Elasticsearch 运维
        • Filebeat 运维
        • Elasticsearch
        • Elastic 技术栈之 Filebeat
        • Logstash 运维
        • Elastic 快速入门
        • Kibana 运维
      • Java IDE
        • Eclipse 应用指南
        • Intellij IDEA 应用指南
        • vscode 应用指南
      • test
        • JMeter 应用指南
    • 附录
      • resources
    • Java Tutorial
    • java-tutorial
  • codes
    • javatool
      • javatool-server
    • javalib
      • Lombok 应用指南
Powered by GitBook
On this page
  • 简介
  • 什么是 Freemark?
  • 入门
  • 创建 Configuration 实例
  • 创建数据模型
  • 获取模板
  • 合并模板和数据模型
  • 完整示例
  • 基础
  • 数值
  • 类型
  • 模板
  • 参考资料

Was this helpful?

  1. 简介
  2. Java 库

Freemark 应用指南

PreviousJavaMail 应用指南NextLombok 应用指南

Last updated 5 years ago

Was this helpful?

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

简介

什么是 Freemark?

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

简言之:模板 + 数据 = 输出

入门

创建 Configuration 实例

首先,你应该创建一个 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 来构建哈希表。

示例:

// 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 直接忽略, 更不会在输出内容中显示。

🔔 注意:

  • 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 就会拒绝执行模板,同时抛出错误信息。

表达式

插值

插值的使用格式是: ${*expression*},这里的 *expression* 可以是所有种类的表达式(比如 ${100 + x})。

表达式的结果必须是字符串,数字或者日期/时间/日期-时间值, 因为(默认是这样)仅仅这些值可以被插值自动转换为字符串。其它类型的值 (比如布尔值,序列)必须 "手动地" 转换成字符串(后续会有一些建议), 否则就会发生错误,中止模板执行。

⭕ <#include "/footer/${company}.html">

⭕ <#if big>...</#if>

❌ <#if ${big}>...</#if>

❌ <#if "${big}">...</#if>

参考资料

img

使用自定义的 bean 类来构建哈希表,bean 中的项和 bean 的属性对应。比如, product 的 price 属性 (getProperty())可以通过 product.price 获取。(bean 的 action 也可以通过这种方式拿到; 要了解更多可以参看 )

模板代表了 freemarker.template.Template 实例。典型的做法是从 Configuration 实例中获取一个 Template 实例。无论什么时候你需要一个模板实例, 都可以使用它的 getTemplate 方法来获取。在 设置的目录中的 test.ftl 文件中存储 ,那么就可以这样来做:

这会向你的终端输出你在模板开发指南部分的 中看到的内容。

img

事实上,指令有两种类型: 和 。 对于用户自定义的指令使用 @ 来代替 #。

FreeMarker 会忽略 FTL 标签中多余的 。

以下为快速浏览清单,如果需要了解更多细节,请参考。

: "Foo" 或者 'Foo' 或者 "It's \"quoted\"" 或者 'It\'s "quoted"' 或者 r"C:\raw\string"

: 123.45

: true, false

: ["foo", "bar", 123.45]; 值域: 0..9, 0..<10 (或 0..!10), 0..

: {"name":"green mouse", "price":150}

: user

: user.name, user["name"]

: products[5]

: .main

: "Hello ${user}!" (或 "Hello " + user + "!")

: name[0]

包含结尾: name[0..4],不包含结尾: name[0..<5],基于长度(宽容处理): name[0..*5],去除开头:name[5..]

: users + ["guest"]

:包含结尾: products[20..29], 不包含结尾: products[20..<30],基于长度(宽容处理):products[20..*10],去除开头: products[20..]

: passwords + { "joe": "secret42" }

: (x * 1.5 + 10) / 2 - y % 100

: x == y, x != y, x < y, x > y, x >= y, x <= y, x lt y, x lte y, x gt y, x gte y, 等等。。。。。。

: !registered && (firstVisit || fromEurope)

: name?upper_case, path?ensure_starts_with('/')

: repeat("What", 3)

: name!"unknown" 或者 (user.name)!"unknown" 或者 name! 或者 (user.name)!

: name?? 或者 (user.name)??

: =, +=, -=, *=, /=, %=, ++, --

插值是用来给 *表达式* 插入具体值然后转换为文本(字符串)。插值仅仅可以在两种位置使用:在 (比如 <h1>Hello ${name}!</h1>) 和 (比如 <#include "/footer/${company}.html">)中。

注意:插值 仅仅 在 (比如 <h1>Hello ${name}!</h1>) 和 中起作用。

这里
之前
示例模板
第一个示例
源码
方法和函数
用户自定义指令
结点
预定义指令
用户自定义指令
空白标记
这里
直接指定值
字符串
数字
布尔值
序列
哈希表
检索变量
顶层变量
从哈希表中检索数据
从序列中检索数据
特殊变量
字符串操作
插值(或连接)
获取一个字符
字符串切分:
序列操作
连接
序列切分
哈希表操作
连接
算术运算
比较运算
逻辑操作
内建函数
方法调用
处理不存在的值
默认值
检测不存在的值
赋值操作
文本 区
字符串表达式
文本区
字符串
http://freemarker.foofun.cn/
简介
什么是 Freemark?
入门
创建 Configuration 实例
创建数据模型
获取模板
合并模板和数据模型
完整示例
基础
数值
类型
模板
参考资料