FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:
1. 文本:直接输出的部分
1. 注释:<#– … –>格式部分,不会输出
1. 插值:即${…}或#{…}格式的部分,将使用数据模型中的部分替代输出
1. FTL指令:FreeMarker指定,和HTML标记类似,名字前加#予以区分,不会输出


常用指令

if指令

if指令进行条件输出控制,类似程序语言中的if语句。

<#if username == "boss">Hi boss!</#if>  
<#if username == "boss">Hi boss!<#else>Hi!</#if>
switch , case , default , break指令

这些指令显然是分支指令,作用类似于Java的switch语句,switch指令的语法结构如下:

<#switch value> 
    <#case refValue>...<#break> 
    <#case refValue>...<#break> 
    <#default>... 
</#switch>
assign指令

assign指令用来定义一个变量并给其赋值,或者替换原有变量的值

<#assign username="master">
include指令

使用include指令,我们可以在当前的模板中插入其他文件的内容。

<#include "/copyright_footer.html">

被包含进来的文件,既可以是静态页,也可以是动态页(即ftl模板)。include指令会先将该文件内容包含进当前模板,然后再跟数据模型结合输出。

noparse指令

noparse指令指定FreeMarker不处理该指定里包含的内容,该指令的语法格式如下:
<#noparse>…

<#noparse> 
<#list books as book> 
   <tr><td>${book.name}<td>作者:${book.author} 
</#list> 
</#noparse>

输出如下:

<#list books as book> 
   <tr><td>${book.name}<td>作者:${book.author} 
</#list>
setting指令

该指令用于设置FreeMarker的运行环境,该指令的语法格式如下:<#setting name=value>,在这个格式中,name的取值范围包含如下几个:
- locale:该选项指定该模板所用的国家/语言选项
- number_format:指定格式化输出数字的格式
- boolean_format:指定两个布尔值的语法格式,默认值是true,false
- date_format,time_format,datetime_format:指定格式化输出日期的格式
- time_zone:设置格式化输出日期时所使用的时区

macro , nested , return指令

macro可以用于实现自定义指令,通过使用自定义指令,可以将一段模板片段定义成一个用户指令,使用macro指令的语法格式如下:

<#macro name param1 param2 ... paramN> 
... 
<#nested loopvar1, loopvar2, ..., loopvarN> 
... 
<#return> 
... 
</#macro> 

在上面的格式片段中,包含了如下几个部分: 
name:name属性指定的是该自定义指令的名字,使用自定义指令时可以传入多个参数 
paramX:该属性就是指定使用自定义指令时报参数,使用该自定义指令时,必须为这些参数传入值 
nested指令:nested标签输出使用自定义指令时的中间部分 
nested指令中的循环变量:这此循环变量将由macro定义部分指定,传给使用标签的模板 
return指令:该指令可用于随时结束该自定义指令.

看如下的例子:

<#macro book>   //定义一个自定义指令 
j2ee 
</#macro> 
<@book />    //使用刚才定义的指令 
上面的代码输出结果为:j2ee

在上面的代码中,可能很难看出自定义标签的用处,因为我们定义的book指令所包含的内容非常简单,实际上,自定义标签可包含非常多的内容,从而可以实现更好的代码复用.此外,还可以在定义自定义指令时,为自定义指令指定参数,看如下代码:

<#macro book booklist>     //定义一个自定义指令booklist是参数 
    <#list booklist as book> 
       ${book} 
    </#list> 
</#macro> 
<@book booklist=["spring","j2ee"] />   //使用刚刚定义的指令 
上面的代码为book指令传入了一个参数值,上面的代码的输出结果为:spring j2ee
t, lt, rt
  • t (整体削减):忽略本行中首和尾的所有空白。
  • lt (左侧削减):忽略本行中首部所有的空白。
  • rt (右侧削减):忽略本行中尾部所有的空白。
    例如
1 <#t>
  2<#t>
  3<#lt>
  4
  5<#rt>
  6

将会输出

1 23
  4
  5  6

数字格式化插值

数字格式化插值可采用#{expr;format}形式来格式化数字,其中format可以是:
- mX:小数部分最小X位
- MX:小数部分最大X位

如下面的例子:

<#assign x=2.582/> 
<#assign y=4/> 
#{x; M2} <#-- 输出2.58 --> 
#{y; M2} <#-- 输出4 --> 
#{x; m2} <#-- 输出2.6 --> 
#{y; m2} <#-- 输出4.0 --> 
#{x; m1M2} <#-- 输出2.58 --> 
#{x; m1M2} <#-- 输出4.0 -->
Map连接运算符

Map对象的连接运算符也是将两个Map对象连接成一个新的Map对象,Map对象的连接运算符是+,如果两个Map对象具有相同的key,则右边的值替代左边的值.看如下的例子:

<#assign scores = {"语文":86,"数学":78} + {"数学":87,"Java":93}>

语文成绩是scores.语文数学成绩是{scores.数学}
Java成绩是${scores.Java}

输出结果是:

语文成绩是86 
数学成绩是87 
Java成绩是93
算术运算符

FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , % 看如下的代码:

<#assign x=5> 
${ x * x - 100 } 
${ x /2 } 
${ 12 %10 }

输出结果是:

-75   2.5   2

在表达式中使用算术运算符时要注意以下几点:
1. 运算符两边的运算数字必须是数字
1. 使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3 + “5”},结果是:35

使用内建的int函数可对数值取整,如:

<#assign x=5> 
${ (x/2)?int } 
${ 1.1?int } 
${ 1.999?int } 
${ -1.1?int } 
${ -1.999?int } 
结果是:2 1 1 -1 -1
字符串内建函数

FreeMarker还提供了一些内建函数来转换输出,可以在任何变量后紧跟?,?后紧跟内建函数,就可以通过内建函数来轮换输出变量.下面是常用的内建的字符串函数:
1. html:对字符串进行HTML编码
1. cap_first:使字符串第一个字母大写 例:var?cap_first
1. lower_case:将字符串转换成小写 例:var?lower_case
1. upper_case:将字符串转换成大写 例:var?upper_case
1. trim:去掉字符串前后的空白字符 例:var?trim
2. length:获取字符串长度 例:var?length
3. capitalize:每个单词的首字符大写 例:var?capitalize
4. contains如果函数中的参数指定的子串出现在源字符串中, 那么返回true。比如:

<#if "piceous"?contains("ice")>It contains "ice"</#if>

out It contains "ice"
  1. split:它被用来根据另外一个字符串的出现将原字符串分割成字符串序列。 比如:
<#list "someMOOtestMOOtext"?split("MOO") as x>
    ${x}
</#list>

输出
some
test
text
日期内建函数
  1. date, time, datetime (当用于日期/时间/日期-时间值时)
  • date:仅日期部分,没有一天当中的时间部分。
  • time:仅一天当中的时间部分,没有日期部分。
  • datetime:日期和时间都在
  1. string (当用于日期/时间/日期-时间值时)
${lastUpdated?string["dd.MM.yyyy, HH:mm"]}
${lastUpdated?string["EEEE, MMMM dd, yyyy, hh:mm a '('zzz')'"]}
${lastUpdated?string["EEE, MMM d, ''yy"]}
${lastUpdated?string.yyyy} <#-- Same as ${lastUpdated?string["yyyy"]} -->
将输出
08.04.2003 21:24
Tuesday, April 08, 2003, 09:24 PM (PDT)
Tue, Apr 8, '03
2003
布尔内建函数
  1. then
<#assign foo = true>
${foo?then('Y', 'N')}

<#assign foo = false>
${foo?then('Y', 'N')}

<#assign x = 10>
<#assign y = 20>
<#-- Prints 100 plus the maximum of x and y: -->
${100 + (x > y)?then(x, y)}

输出
Y

N

120
序列内建函数
  1. join:使用给定的分隔符来连接序列中的项为一个独立的字符串
<#assign colors = ["red", "green", "blue"]>
${colors?join(", ")}

输出
red, green, blue
  1. seq_contains:辨别序列中是否包含指定值。它包含一个参数,就是来查找的值
<#assign x = ["red", 16, "blue", "cyan"]>
"blue": ${x?seq_contains("blue")?string("yes", "no")}
"yellow": ${x?seq_contains("yellow")?string("yes", "no")}
16: ${x?seq_contains(16)?string("yes", "no")}
"16": ${x?seq_contains("16")?string("yes", "no")}

输出
"blue": yes
"yellow": no
16: yes
"16": no
  1. size:获取序列中元素的个数
哈希表内建函数
  1. keys
<#assign h = {"name":"mouse", "price":50}>
<#assign keys = h?keys>
<#list keys as key>${key} = ${h[key]}; </#list>

输出
name = mouse; price = 50;
  1. values:一个包含哈希表中子变量的序列。 注意并不是所有的哈希表都支持这个 ,至于返回的值的顺序,和内建函数 keys 的应用是一样的;看看上面的叙述就行了。
循环变量内建函数
  1. counter:返回当前迭代(由循环变量名称识别)从1开始的索引。
<#list ['a', 'b', 'c'] as i>
  ${i?counter}: ${i}
</#list>

输出
    1: a
    2: b
    3: c
  1. index:返回当前迭代(由循环变量名称识别)从0开始的索引。
<#list ['a', 'b', 'c'] as i>
  ${i?index}: ${i}
</#list>

输出
    0: a
    1: b
    2: c
  1. is_first:辨别循环项是否是当前迭代(由循环变量名称识别)的第一项。
<#list ['a', 'b', 'c'] as i>${i?is_first?c} </#list>

输出
true false false
  1. is_last:辨别循环项是否是当前迭代(由循环变量名称识别)的最后一项。
<#list ['a', 'b', 'c'] as i>${i?is_last?c} </#list>

输出
false false true
空值处理运算符

FreeMarker对空值的处理非常严格,FreeMarker的变量必须有值,没有被赋值的变量就会抛出异常,因为FreeMarker未赋值的变量强制出错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误.这里所说的空值,实际上也包括那些并不存在的变量,对于一个Java的 null值而言,我们认为这个变量是存在的,只是它的值为null,但对于FreeMarker模板而言,它无法理解null值,null值和不存在的变量完全相同.

为了处理缺失变量,FreeMarker提供了两个运算符:
- !:指定缺失变量的默认值
- ??:判断某个变量是否存在

其中,!运算符的用法有如下两种:

variable!或variable!defaultValue,第一种用法不给缺失的变量指定默认值,表明默认值是空字符串,长度为0的集合,或者长度为0的Map对象.

使用!指定默认值时,并不要求默认值的类型和变量类型相同.使用??运算符非常简单,它总是返回一个布尔值,用法为:variable??,如果该变量存在,返回true,否则返回false