理解数值和类型的概念是理解数据模型的关键和基础。本节主要内容如下:
这部分对于程序员来说可以直接跳过的。
正如你知道的,来自于每天所使用的数字,比如 50,0.5 等这些用语就是数值的示例,也就是数字。在计算机语言中, 这些用语有着更广泛的含义,比如数值并不一定是数字类型值,比如下面这个数据模型:

变量 message、foo、size 的 value 均是字符串,其中 price 的 value 均是数字,而 misc、animals、mouse、elephant、python 的 value 均是 Hash 均是一个哈希表。所以说,数值就是存储在变量中的 (比如,在 misc 或 message 或 animals 中的值) 那些值。但是,不需要存储于变量之中的数值也可以称之为数值,比如下面的数字 100:
<#if cargo.weight < 100>Light cargo</#if>
当模板被执行时,计算出的临时结果也称为数值,如下:
${cargo.weight / 2 + 100}数值中非常重要的一个概念就是类型。比如,变量 message、foo、size 的 value 均是字符串,其中 price 的 value 均是数字。数值的类型这个概念非常的重要,因为它决定了这些数值可以在哪里使用的最大限度,以及在某个变量上面能够使用的内置函数,比如:你不能在字符串类型变量上面引用数学内置函数。 比如,使用 ${message / 2} 就是错误的,但是使用 ${price / 2} 就能计算出结果,因为算术中的除法仅对数字类型的值有效,而不能用于字符串。仅当 animals 是一个哈希表变量时,表达式 animals.mouse 才是有效的。也可以用 <#list ...> 指令来遍历序列。而 <#if ...> 指令的条件只能是布尔值等。
FreeMaker 提供如下基础数据类型:
字符串:表示简单的文本,例如:产品的名称。如果想在模板中直接给出字符串值,而不是使用数据模型中的变量, 那么将文本内容写在引号内即可,如 "It is a test" 或 'It is a test'。
数值:如产品的价格,员工的收入、每月的房租。 FreeMaker是不区分整数和非整数的,只有单一的数字类型。如果要在模板中直接给出具体的数字,那么可以这么来写: 150 或 -90.05 或 0.001。
布尔值:布尔值代表了逻辑上的对或错 (是或否)。如:用户是否登录了。 我们常使用布尔值作为 if 指令的条件, 比如 <#if isLogin>...</#if> 或者 <#if price == 0>...</#if>; 后面这个 price == 0 部分的结果就是布尔值。在模板中可以直接使用保留字 true 和 false 来指定布尔值。
日期:日期变量可以存储和日期/时间相关的数据。 一共有三种变化:
日期:精确到天的日期,没有时间部分。比如:2020-02-02。
时间:精确到毫秒,没有日期部分。比如:10:19:18 PM。
日期-时间 (有时也被称为 "时间戳"),比如:2020-02-02 10:19:18。
注意:FreeMarker 区别字符串,数字,布尔值和日期类型的值。比如,字符串 "150" 看起来很像数字 150,字符串只是字符的任意序列,不能将它用于计算目的,也不能和其它数字进行比较等等。
高级数据类型是用来包含其他变量,这些变量可以是基础数据类型,也可以是高级数据类型。容器的类型有:
哈希表:每个子变量都可以通过一个唯一的名称来查找。 这个名称是不受限制的字符串。哈希表并不确定其中子变量的顺序。 也就是说没有第一个子变量,第二个子变量这样的说法等;变量仅仅是通过名称来访问的,类似 Java语言中的 HashMap、HashTable 一样,不记录内部元素的顺序, 仅仅通过名称来访问。
序列:序列也可以称为列表、数组,每个子变量通过一个整数来标识。第一个子变量的标识符是0, 第二个是1,第三个是2,这样来类推,而且子变量是有顺序的。这些数字(如0、1、2)通常被称为索引。
集合:从模板设计者角度来看,集合是有限制的序列。不能获取集合的大小, 也不能通过索引取出集合中的子变量,而且集合也是没有顺序的,但是它们仍然可以通过 list 指令来遍历。
下面通过实例来演示哈希表、序列、集合、以及基础数据类型的用法。如下:
(1)模版内容
<html>
<head>
<title>Book List</title>
</head>
<body>
<h1>${title} —— ${date?string('dd.MM.yyyy HH:mm:ss')}</h1>
<p>书籍列表:</p>
<table>
<tr>
<th>名称</th>
<th>价格</th>
</tr>
<#list books as book <#-- 打印书籍列表 -->>
<tr>
<td>${book.name <#-- 书名 -->}</td>
<td>${book.price <#-- 书价格 --> }</td>
</tr>
</#list>
</table>
<p>
作者:<#list authors as author>author<#sep>, </#list>
</p>
</body>
</html>(2)Java 代码
package com.hxstrive.freemarker.demo1;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.*;
public class Demo5 {
public static void main(String[] args) throws Exception {
// 1. 配置 FreeMarker
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setClassForTemplateLoading(Demo5.class, "/templates/");
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.CHINESE);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// 2. 准备模版数据
Map<String, Object> input = new HashMap<String, Object>();
input.put("title", "编程书籍推荐"); // 字符类型
input.put("date", new Date()); // 日期类型
List<Map<String,Object>> bookList = new ArrayList<Map<String,Object>>();
input.put("books", bookList); // 序列
Map<String,Object> javaBook = new HashMap<String, Object>();
javaBook.put("name", "Java高级编程");
javaBook.put("price", 67.5f);
bookList.add(javaBook); // Hash 类型
Set<String> authors = new HashSet<String>();
authors.add("张三");
authors.add("李四");
input.put("authors", authors); // 集合类型
Template template = cfg.getTemplate("template5.ftl");
Writer consoleWriter = new OutputStreamWriter(System.out);
template.process(input, consoleWriter);
// 将输出结果保存到文件中
Writer fileWriter = new FileWriter(new File("output.html"));
try {
template.process(input, fileWriter);
} finally {
fileWriter.close();
}
}
}(3)输出结果
<html> <head> <title>Book List</title> </head> <body> <h1>编程书籍推荐 —— 21.06.2020 10:30:03</h1> <p>书籍列表:</p> <table> <tr> <th>名称</th> <th>价格</th> </tr> <tr> <td>Java高级编程</td> <td>67.5</td> </tr> </table> <p> 作者:author, author </p> </body> </html>
注意:${date?string('dd.MM.yyyy HH:mm:ss')} 用到了 FreeMaker 内置函数 string,使用该内置函数将日期格式化成固定格式的字符串。