理解数值和类型的概念是理解数据模型的关键和基础。本节主要内容如下:
这部分对于程序员来说可以直接跳过的。
正如你知道的,来自于每天所使用的数字,比如 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,使用该内置函数将日期格式化成固定格式的字符串。