FreeMaker Quick Start
(本人翻译,希望与大家一起分享,如果有错误,请不吝赐教!谢谢)
第一章 开始
Template + data-model = output
数据模型概述
模板概述
本章内容是粗略的介绍了FreeMarker。本章介绍的内容都不涉及技术细节,但是读过本章后,你可以做出简单又实用的FreeMaker模板了。
Template + data-model = output
假设你的网上购物项目需要如下一个HTML页面:
|
|
| |
|
|
| |
|
|
|
在这个页面中,欢迎信息中的用户名(这里是“Big Joe”)应显示登录的用户姓名,而且最新的产品“green mouse”应该动态的从数据库中获取,这就意味着它的信息可能随时改变。在这种情况下,你就不能够实用静态页面,把这些信息直接编码在HTML中。
对于以上的情况,FreeMaker的解决方法是使用一个模板来代替静态页面。模板与静态页面很相似,不同的是它包含了一些FreeMaker的动态标签:
|
| ||
|
|
| |
|
|
|
这个模板保存在服务器端,与通常的静态页面相同。但是当有请求访问时,FreeMaker会把模板内的 ${...}更新为对应的对象属性或数值(例如,将${user}翻译成访问者的信息),翻译成普通的静态页面,将结果显示在用户的浏览器中。因此,此时用户的浏览器上收到的信息会是类似于我们第一个HTML的页面,而且用户不会感到我们在服务器端使用了FreeMaker。但是模板本身在这次使用过程中不会发生变化,因此这个模式可以重用,为每个访问者创建他们自己的页面。而且信息总是最新的。
现在,我们来看看数据是如何从内存中写到页面上的。FreeMaker的思想是遵从页面与业务逻辑分离的,因此在模板中我们只解决如何显示的问题,而数据的组织是在FreeMaker之外,通常是JAVA或其他语言编写的程序来负责的。因此模板的编写者不用关心数据将如何得到,所以FreeMaker的模板有更强的重用性。
FreeMaker和制作模板的人员虽然不关心数据的来源,但是他们仍然知道模板中要使用的数据是什么。所有的模板可用数据被包装在数据模型(data-model)中。数据模型的存储方式是一个树形,如下:
|
|
| |
|
|
| |
|
|
|
最后,我们总结一下:FreeMaker通过模板(template)和数据模型(data-model)构建静态页面:Template + data-model = output
像我们看到的,数据模型以树形方式存储数据,它可以任意扩展深度和广度:
|
| ||
|
|
| |
|
|
|
那些类似根节点的变量(如 root, animals, mouse, elephant, python, whatnot)我们称为哈希表(hashes,很像java中的map)。哈希表利用唯一关键字(如, "animals", "mouse" or "price")存储变量
那些存储单个变量值的单位(如size, price, test and because)称为标量。
当你想在模板里使用已有的变量时,只要写出它们的“路径”,用“.”把路径连接起来。例如,我们要访问例子中的mouse的price时,“路径”为animals.mouse.price,再写入符号${…..}内,这时FreeMaker就可以根据我们提供的信息取出对应的数据了。
除了哈希表外,FreeMaker有另外一种存储方式:序列(sequences)。序列与哈希表很相似(本人觉得更像数组),不同的是它存储变量的方式不是利用关键字,而是顺序的将变量存储起来。例如,在下面的数据模型中,animals 和 whatnot.fruits属于序列:
|
| ||
|
|
| |
|
|
|
访问序列中变量的方式是将它们(变量)的位置用数字标识,并且用“[ ]”括起来,写在它们的“路径”后。变量起始位置的数字标识为“0”(或者说从0开始),所以与JAVA中的数组相同,例如我们要得到上面例子中第一个animals中的变量的名称时,应该这样标示:animals[0].name。而要得到whatnot.fruits中第二个变量的名称时应该这样表示:whatnot.fruits[1].。
标量可以更细的分为下列类型:
· String:字符串类型。
· Number:数字类型。
· Date/time:日期类型。
· Boolean:布尔类型。
总结:
· 数据模型可以被表述为树形。
· 标量是指存储基本类型变量(字符串类型、数字类型、日期类型或布尔类型)的数据模型。
· 哈希表利用唯一关键字存储标量。
· 序列顺序存储标量,变量的值可以通过它在序列中的位置得到。
最简单的模板是空白的HTML文件(或者是任何空白文档文件—FreeMaker并没有限制一定是HTML)。当客户端访问这个页面时,FreeMaker将发送HTML到客户端。如果你希望你的网页可以动态的展示信息,那么我们要了解模板中的运算符(或者是标签)如何使用。
· ${……}:FreeMaker基本运算符。FreeMarker在翻译时会将运算符用变量的数值替换,这个过程我们成为转译(interpolations)。
· FTL 标签(FreeMarker语言的标签)::标签。FTL 标签有点像HTML标签,但是它们作为FreeMaker的运算符,在生成的HTML中不会看到。它们以“#”开头(用户定义的标签用“@”开头而不是“#”,我们现在先不讨论用户自定义标签)。
· 注释:与HTML注释类似,但是FreeMaker的注释是以 <#--开头,以-->结束的。所有注释中的内容都会被FreeMaker忽略,也不会被转译并发送到客户端。
在页面中,除了上述所说的内容我们都认为是静态的信息,都不会被FreeMaker转译而直接发送到客户端。
FTL标签也被称为标识(directives)。它和HTML标签的语法相同(如<table> and </table>),都要求标签闭合。
标识的例子
尽管FreeMaker有很多的标识,但是在这里我们只关注其中的最常用的三个标识。
if 标识
使用if标识,我们可以根据条件的显示模板中的内容。下面我们稍微修改一下第一个例子,只有我们的老板Big Joe访问时出现问候语“我们深受爱戴的领导啊~!”(老外也会拍马屁):
|
|
| |
|
|
| |
|
|
|
上面的if标识告诉FreeMaker,“our beloved leader”这句马屁在用户名为“Big Joe”时出现,而如果user == "Big Joe"条件不满足时,则不显示在<#if condition> 和</#if>中间的内容。
我们在上面的例子中看到,“==”是用来验证其左面的变量值是否与右面的值相等,之后为标识返回一个布尔值。“==”的左边是一个已知变量,右面放置的是一个字符串,在FreeMaker中,所有的字符串必须用引号括起来。
下面的例子:只有animals.python.price为0时,"Pythons are free today!"才会被输出。
|
|
| |
|
|
| |
|
|
|
与上面的例子类似,这次判断的变量类型为数字类型,需要注意的是,如果我们把等号右边写成“0”,则FreeMaker将做出错误的判断,认为animals.python.price为字符串类型。
如果变量的price值不为 0时,"Pythons are not free today!"会被打印:
|
|
| |
|
|
| |
|
|
|
显而易见,“!=”标识不等于。
我们也可以这样组织判断条件:
|
|
| |
|
|
| |
|
|
|
在if标识中还可以加入 <#else> 标签,让我们可以做更多的事情,如:
|
|
| |
|
|
| |
|
|
|
条件animals.python.price < animals.elephant.price满足时输出“This prints ''Pythons are cheaper than elephants today.''反之则输出 ''Pythons are not cheaper than elephants today.''
如果我们有个布尔类型的变量,则可以直接作为if标识的判断条件,例如:
|
|
| |
|
|
| |
|
|
|
List标识
很显然,list用来显示一列表。例如,如果我们用下面这个模板展示上面的序列的数据的话:
|
|
| |
|
|
| |
|
|
|
输入的内容如下:
|
|
| |
|
|
| |
|
|
|
标准的list标识的标签语法如下:
<#list sequence as loopVariable>repeatThis</#list>
在repeatThis位置的数据将被循环输出,直至循环结束。我们可以在这个位置组织我们的数据。loopVariable作为局部变量,只存在于<#list ...>和</#list>标签中。
下一个例子中,我们列出所有的fruits数据:
|
|
| |
|
|
| |
|
|
|
表达式whatnot.fruits 我们现在应该知道它的含义了。
include 标识
使用include标识,我们可以将其他的内容加入到模板中来。
假设我们要在多个页面中展示相同的内容,我们可以创建一个关于这个内容的文件,之后将这个文件引入到每个要求展示的地方。例如,我们可以把版权声明信息单独提取出来,写入文件copyright_footer.html中:
|
|
| |
|
|
| |
|
|
|
当我们需要展示版权声明时,在页面用include标识引入即可:
|
|
| |
|
|
| |
|
|
|
此时页面的输入为:
|
|
| |
|
|
| |
|
|
|
如果我们修改copyright_footer.html文件,那么所有页面的版权信息将都会改变。
综合使用标识
我们可以根据页面的需要多次使用标识,而且标识之间也支持嵌套。例如,我们要列出所有animals并使用大一号的字体标识出size值为large的animal的名称:
|
|
| |
|
|
| |
|
|
|
注意:FreeMaker将不会对运算符、标识和注释外的文字做任何操作,不会对font标签有任何影响。
对“无法找到”的变量的处理
在实际开发过程中,数据模型中存储的变量是无法预知的。对于没有明确标明的 “无法找到”的变量,FreeMaker无法正常运行。下面列出两种FreeMaker典型的处理方式:
提示:一个不存在的变量和一个null值的变量在FreeMaker看来都是一样的,因此我们用“无法找到”这个词来统一描述。
方法一:使用默认值。当我们引用一个变量时,我们可以设置这个变量的默认值,默认值在变量“无法找到”时生效,方法是在变量后用“!”操作符将变量与默认值连接。像下面的例子,当user变量在数据模型中“无法找到”时,模板将认为user的值为"Anonymous":
|
|
| |
|
|
| |
|
|
|
方法二:用if标识判断。我们可以在使用变量之前用if标识判断变量是否“无法找到”,具体格式是在if标签中的条件位置上引用变量名,并用“??”连接,如:
|
|
| |
|
|
| |
|
|
|
关于多层变量的访问方式,如animals.python.price;表达式 animals.python.price!0 只有在 animals.python存在的条件下才是正确的。 只有在最后一个变量“无法找到”时,这里的“!”操作符才生效(python也可能“无法找到”),因此这种情况下,我们在赋默认值时应该使用下面的格式: (animals.python.price)!0。同样的,在if标识中??操作符应这样使用: (animals.python.price)??.