http://freemarker.org/docs/dgui_quickstart.html
data-model
1、data-model可以被看做是树形结构
2、scalars存储一个特定的值。这个值可以是string、number、date-time/date/time、boolean.
3、hashes是一个容器,存储其他变量并且关联一个唯一的索引名。
4、sequences是一个容器,存储其他变量在一个有序序列中。存储的变量可以通过数字化索引值获取到,索引从0开始。
(root)
|
+- animals
| |
| +- mouse
| | |
| | +- size = "small"
| | |
| | +- price = 50
| |
| +- elephant
| | |
| | +- size = "large"
| | |
| | +- price = 5000
| |
| +- python
| |
| +- size = "medium"
| |
| +- price = 4999
|
+- message = "It is a test"
|
+- misc
|
+- foo = "Something"
hashes :看起来像目录的variable(如root、animals、mouse、elephant、Python、misc)叫做hashes.
sub-variables :hashes存储的其他variable,叫做subvariable
lookup-name :hashes通过一个lookup name存储sub variables。如animals、mouse、elephant、Python。
虽然lookup-name就是hashes,但有种情况是没有lookup-name的variable——sequences
sequences :相对于hashes,是另一种重要的variables。他们存储subvariables跟hashes一样,但是这里的subvariables没有名字(lookup-name),他们只是list中的items,例如下面的animals和misc.fruits就是sequences。
(root)
|
+- animals
| |
| +- (1st)
| | |
| | +- name = "mouse"
| | |
| | +- size = "small"
| | |
| | +- price = 50
| |
| +- (2nd)
| | |
| | +- name = "elephant"
| | |
| | +- size = "large"
| | |
| | +- price = 5000
| |
| +- (3rd)
| |
| +- name = "python"
| |
| +- size = "medium"
| |
| +- price = 4999
|
+- misc
|
+- fruits
|
+- (1st) = "orange"
|
+- (2nd) = "banana"
template
最简单的template是一个单纯的html文件(诸如此类的text文件,freemarker并不不局限于html),当客户端访问页面时,freemarker会将该html发送到客户端。
但是,如果我们希望该页面更动态化,那么我们开始放一些freemarker能读懂的特殊的部分在html中:
1、${...} :freemarker将替换花括号内的计算结果的结果输出。叫做interpolations
2、FTL tags(FreeMarker Template Language tags) :FTL标签有点类似HTML标签,是一些freemarker的指令,并且不会被输出。这些标签是以#开头,如果是自定义标签则是以@开头。
3、Comments :freemarker的注解类似于HTML的注解,不过它是用<#-- -->格式。和HTML注解不同的是,它不会输出(访问者在page sources中看不到它),因为freemarker会跳读这部分。
对于非FTL标签、非interpolation、非Comment,freemarker将视为静态文本,不会对其解译,只会原样输出。
关于FTL标签,我们就得提到所谓的directives. directives与FTL标签的关系就等同于Html标签(<table></table>)与Html元素(table元素)之间的关系。
这里提供给大家一个可以轻松编写template的网址:http://freemarker-online.kenshoo.com/
一些基本的directives:
接下来我们看一下一些基本的常用的directives,全部的directive看这里Directive Reference
1、if 指令
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#elseif animals.elephant.price < animals.python.price>
Elephants are cheaper than pythons today.
<#else>
Elephants and pythons cost the same today.
</#if>
2、list 指令
<ul>
<#list misc.fruits as fruit>
<li>${fruit}
</#list>
</ul>
看这里,避免misc.fruits为空的情况,<ul></ul>依然会输出的问题,可以如下:
<#list misc.fruits>
<ul>
<#items as fruit>
<li>${fruit}
</#items>
</ul>
</#list>
除了上面提到的
item 指令,另外一个与list相关的常用指令:
sep
Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, </#list>
Fruits: orange, banana
sep指令只有在有下一个值的时候才会输出,所以banana后没有逗号。
再看这里,如果misc.fruits为空怎么办?只打印fruit的话,空就不太合适了。其实list,就像if,可以有一个else指令:
<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, <#else>None</#list>
综上所述,所有这些指令(list、item、sep、else)可以一起用:
<#list misc.fruits>
<p>Fruits:
<ul>
<#items as fruit>
<li>${fruit}<#sep> and</#sep>
</#items>
</ul>
<#else>
<p>We have no fruits.
</#list>
通过include指令,我们可以插入另一个文件内容到当前template。
料想我们需要在多个页面显示copyright通知,我们可以创建一个只包含copyright的文件,然后在任何我们需要copyright通知的地方插入这个文件。
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>
使用built-ins(内置):
所谓的built-ins如同subvariables(或者相当于java术语中的methods),并不是来自于data-model中的subvariables,而是由freemarker添加到前面的值上的。
为了清晰subvariables的来源是built-ins还是data-model,我们必须用?(问号)替换 . (点)来访问这些subvariables。
下面列举一下最常用的built-ins :
1、user?upper_case :给出user的大写格式(如John,替换为JOHN)。
2、user?cap_first :给出user的首字母大写(如john,替换为John)。
3、user?length :给出user字符的长度(如,john,返回4)。
4、animals?size :给出animals sequences的items数量(上面sequences的data-model中数量是3。mouse、elephant、Python)。
5、如果是在<#list animals as animal>与对应的</#list>标签之间:
5.1、animal?index :给出基于0的animal在animals中的索引。
5.2、animal?counter :类似于index,只不过是基于1的索引。
5.3、animal?item_parity :根据当前counter的奇偶性,给出字符串“odd”(奇数)或“even”(偶数)。
-------通常用于渲染交替色的行,如<td class="${animal?item_parity}Row">
还有一些built-ins,需要传参:
6、animal.protected?string("Y", "N") :返回字符串“Y”或“N”,根据animal.protected的boolean值。
7、animal?item_cycle("lightRow", "darkRow") :较之前提到的item_parity,这个是更为通用的变量。
8、fruits?join(", ") :将list通过串联items转换成一个string,并在每个items间插入参数所指定的分隔符。如,“orange, banana”。
9、user?starts_with("J") :返回boolean值,根据user是否以J开头。
Built-in应用是可以使用串联方式调用的,如,fruits?join(", ")?upper_case 根据先后顺序依次执行,就像串联调用 . -s一样。
这里是全部的built-ins集合 Built-in Reference
处理变量缺失:
1、
<h1>Welcome ${user!"visitor"}!</h1>
2、
<#if user??><h1>Welcome ${user}!</h1></#if>
另外,
animals.python.price!0 可能抛异常“undefined variable”,为避免应:
(animals.python.price)!0
同样,animals.python.price??
应(animals.python.price)??
转义HTML、XML或其他标记:
如果正确配置了freemarker,freemarker会自动转换所有${...}打印的值。配置freemarker就是程序员的职责了,点击查看怎么配置
推荐的做法是通过 ftlh 扩展名来激活html的自动转义,ftlx 扩展名来激活xml的自动转义。