3、模板 
(1)整体结构 
l         模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合: 
Ø         文本:直接输出 
Ø         Interpolation:由${和},或#{和}来限定,计算值替代输出 
Ø         FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出 
Ø         注释:由<#--和-->限定,不会输出 
l         下面是以一个具体模板例子: 
<html>[BR] <head>[BR]   <title>Welcome!</title>[BR] </head>[BR] <body>[BR]   <#-- Greet the user with his/her name -->[BR]   <h1>Welcome ${user}!</h1>[BR]  <p>We have these animals:[BR]   <ul>[BR]   <#list animals as being>[BR]     <li>${being.name} for ${being.price} Euros[BR]  </#list>[BR]   </ul>[BR] </body>[BR] </html>    
l         [BR]是用于换行的特殊字符序列 
l         注意事项: 
Ø         FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的 
Ø         Interpolation只能在文本中使用 
Ø         FTL标记不能位于另一个FTL标记内部,例如: 
<#if <#include 'foo'>='bar'>...</if>  
Ø         注释可以位于FTL标记和Interpolation内部,如下面的例子: 
<h1>Welcome ${user <#-- The name of user -->}!</h1>[BR]<p>We have these animals:[BR] <ul>[BR] <#list <#-- some comment... --> animals as <#-- again... --> being>[BR] ...    
Ø         多余的空白字符会在模板输出时移除 
(2)指令 
l         在FreeMarker中,使用FTL标记引用指令 
l         有三种FTL标记,这和HTML标记是类似的: 
Ø         开始标记:<#directivename parameters> 
Ø         结束标记:</#directivename> 
Ø         空内容指令标记:<#directivename parameters/> 
l         有两种类型的指令:预定义指令和用户定义指令 
l         用户定义指令要使用@替换#,如<@mydirective>...</@mydirective>(会在后面讲述) 
l         FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的: 
<ul> <#list animals as being>   <li>${being.name} for ${being.price} Euros  <#if use = "Big Joe">      (except for you) </#list> </#if> <#-- WRONG! --> </ul>    
l         如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息 
l         FreeMarker会忽略FTL标记中的空白字符,如下面的例子: 
<#list[BR]   animals       as[BR]      being[BR] >[BR] ${being.name} for ${being.price} Euros[BR]</#list    >    
l         但是,<、</和指令之间不允许有空白字符 
(3)表达式 
l         直接指定值 
Ø         字符串 
n         使用单引号或双引号限定 
n         如果包含特殊字符需要转义,如下面的例子: 
${"It's \"quoted\" andthis is a backslash: \\"}   ${'It\'s "quoted" andthis is a backslash: \\'}   
输出结果是: 
It's "quoted" and this is a backslash: \   It's "quoted" and this is a backslash: \   
n         下面是支持的转义序列: 
| 
 转义序列  | 
 含义  |  
| 
 \"  | 
 双引号(u0022)  |  
| 
 \'  | 
 单引号(u0027)  |  
| 
 \\  | 
 反斜杠(u005C)  |  
| 
 \n  | 
 换行(u000A)  |  
| 
 \r  | 
 Return (u000D)  |  
| 
 \t  | 
 Tab (u0009)  |  
| 
 \b  | 
 Backspace (u0008)  |  
| 
 \f  | 
 Form feed (u000C)  |  
| 
 \l  | 
 <  |  
| 
 \g  | 
 >  |  
| 
 \a  | 
 &  |  
| 
 \{  | 
 {  |  
| 
 \xCode  | 
 4位16进制Unicode代码  |   
n         有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子: 
${r"${foo}"}${r"C:\foo\bar"}   
输出的结果是: 
Ø         数字 
n         直接输入,不需要引号 
n         精度数字使用“.”分隔,不能使用分组符号 
n         目前版本不支持科学计数法,所以“1E3”是错误的 
n         不能省略小数点前面的0,所以“.5”是错误的 
n         数字8、+8、08和8.00都是相同的 
Ø         布尔值 
n         true和false,不使用引号 
Ø         序列 
n         由逗号分隔的子变量列表,由方括号限定,下面是一个例子: 
<#list ["winter", "spring", "summer", "autumn"] as x> ${x}</#list>   
输出的结果是: 
n         列表的项目是表达式,所以可以有下面的例子: 
[2 + 2, [1, 2, 3, 4], "whatnot"]  
n         可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号 
n         可以定义反递增的数字范围,如5..2 
Ø         散列(hash) 
n         由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子: 
{"name":"green mouse", "price":150} 
n         键和值都是表达式,但是键必须是字符串 
l         获取变量 
Ø         顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头 
Ø         从散列中获取数据 
n         可以使用点语法或方括号语法,假设有下面的数据模型: 
(root)  |  +- book  |   |  |   +- title = "Breeding green mouses"  |   |  |   +- author  |       |  |       +- name = "Julia Smith"  |       |  |       +- info = "Biologist, 1923-1985, Canada"  |  +- test = "title"   
下面都是等价的: 
book.author.name book["author"].name book.author.["name"] book["author"]["name"]  
n         使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果 
Ø         从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0 
Ø         序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式 
Ø         特殊变量:FreeMarker内定义变量,使用.variablename语法访问 
${"Hello ${user}!"}${"${user}${user}${user}${user}"}   
${"Hello " + user + "!"}${user + user + user + user} 
<#if ${isBig}>Wow!</#if><#if "${isBig}">Wow!</#if> 
${user[0]}${user[4]}${user[1..4]} 
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user> - ${user}</#list>  
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>- Joe is ${ages.Joe}- Fred is ${ages.Fred}- Julia is ${ages.Julia}   
- Joe is 30 - Fred is 25 - Julia is 18    
${x * x - 100}${x / 2}${12 % 10} 
${3 * "5"} <#-- WRONG! -->   
${(x/2)?int}${1.1?int}${1.999?int}${-1.1?int}${-1.999?int} 
<#if x < 12 && color = "green">   We have less than 12 things, and they are green. </#if> <#if !hot> <#-- here hot must be a boolean -->   It's not hot. </#if>    
${test?html}${test?upper_case?html} 
Tom & Jerry TOM & JERRY    
| 
 操作符组  | 
 操作符  |  
| 
 后缀  | 
 [subvarName] [subStringRange] . (methodParams)  |  
| 
 一元  | 
 +expr、-expr、!  |  
| 
 内建  | 
 ?  |  
| 
 乘法  | 
 *、 / 、%  |  
| 
 加法  | 
 +、-  |  
| 
 关系  | 
 <、>、<=、>=(lt、lte、gt、gte)  |  
| 
 相等  | 
 ==(=)、!=  |  
| 
 逻辑and  | 
 &&  |  
| 
 逻辑or  | 
 ||  |  
| 
 数字范围  | 
 ..  |   
<#setting number_format="currency"/> <#assign answer=42/> ${answer}${answer?string}  <#-- the same as ${answer} -->${answer?string.number}${answer?string.currency}${answer?string.percent}  
$42.00 $42.00 42 $42.00 4,200%  
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}${lastUpdated?string("EEE, MMM d, ''yy")}${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}   
2003-04-08 21:24:44 Pacific Daylight Time Tue, Apr 8, '03 Tuesday, April 08, 2003, 09:24:44 PM (PDT)  
<#assign foo=true/> ${foo?string("yes", "no")} 
           <#-- If the language is US English the output is: --> <#assign x=2.582/> <#assign y=4/> #{x; M2}   <#-- 2.58 -->#{y; M2}   <#-- 4    -->#{x; m1}   <#-- 2.6 -->#{y; m1}   <#-- 4.0 -->#{x; m1M2} <#-- 2.58 -->#{y; m1M2} <#-- 4.0  -->   
 
  |