FreeMarker 是一个用Java编写的模板引擎,主要用来生成HTML Web页面,特别是基于MVC模式的应用程序。虽然FreeMarker具有一些编程的能力,但不像PHP,通常由Java程序准备要显示的数据,由 FreeMarker模板生成页面。 FreeMarker可以作为Web应用框架一个组件,但它与容器无关,在非Web应用程序环境也能工作的很好。 FreeMarker适合作为MVC的视图组件,还能在模板中使用JSP标记库。
<
html
>
<
head
>
<
title
>
Welcome!
</
title
>
</
head
>
<
body
>
<
h1
>
Welcome ${ user }!
</
h1
>
<
p
>
Our latest product:
<
a
href
="${ latestProduct.url }"
>
${ latestProduct.name }
</
a
>
!
</
body
>
</
html
>
上 面的例子中,在简单的HTML中加入了一些由${ … }包围的特定FreeMarker的指令,这个文件就称为模板了。而user、 latestProduct.url和latestProduct.name来自于数据模型,由Java程序提供,模板设计者就不用关心数据从哪来的。
FreeMarker模板中可以包括下面四种特定部分:
一.) 文本:直接输出
二.) FTL标记(FreeMarker模板语言标记):类似于HTML标记,名字前加#(有些以 at 开始,用户自定义标记)予以区分,不会输出。
字符串- 使用单引号或双引号限定;如果包含特殊字符需要转义符:${ "It's \"quoted\" andthis is a backslash: \\" }
有一类特殊的字符串:${ r"C:\foo\bar" },输出结构为:C:\foo\bar,在引号前面加r被认为是纯文本。
数字-直接输入,不需要引号。${ 08 }, ${ +8 }, ${ 8 dot 00 } and ${ 8 } 都是相同的
布尔值-true和false,不使用引号
Sequences(序列)-由逗号分隔的变量列表,由方括号限定,类似java中的一维数组:
<
#list
["winter", "spring", "summer", "autumn"] as x
>
${ x }
</
#list
>
输出结果:
winter
spring
summer
autumn
例二:[2 + 2, [1, 2, 3, 4], "whatnot"]
例三:2..5,等同于[2, 3, 4, 5];5..2,等同于[5,4,3,2]。注意方括号是不需要的。
Hashes(散列)-由逗号分隔的键-值列表,由大括号限定,键和值之间用冒号分隔:{ "name":"green mouse", "price":150 },键和值都是表达式,但是键必须是字符串。
获取变量-${ variable },变量名只能是字母、数字、下划线、$、 at 和#的组合,且不能以数字开头。下列表达式是等价的:
book dot author.name
book["author"].name
book.author.["name"]
book["author"]["name"]
获取Sequence(序列)片断-使用[startindex..endindex],例如:seq中存储了"a", "b", "c", "d","e",那么seq[1..2]包含了b和c两个值。
可以使用.variablename语法访问FreeMarker内置变量。
字符串操作
{ "Hello ${ user }!" } <==> ${ "Hello " + user + "!" }
${ "${ user }${ user }${ user }${ user }" } <==> ${ user + user + user + user }
${ … }只能在文本中使用,下面是错误的代码:
<#if ${ isBig }>Wow!</#if>
<#if "${ isBig }">Wow!</#if> //此处的代码也是错误的,因为if指令需要的是boolean,实际的却是个字符串
子字符串的操作,假设user的值为"Big Joe":
${ user[0] }${ user[4] } <==> BJ
${ user[1..4] } <==> ig J
Sequences(序列)操作
<
#list
["Joe", "Fred"] + ["Julia", "Kate"] as user
>
- ${ user }
</
#list
>
结果:
- Joe
- Fred
- Julia
- Kate
Hashes(散列)操作
<
#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的值设定为5 --
>
${ x * x - 100 }
${ x / 2 }
${ 12 % 10 }
结果:
-75
2.5
2
注意: 操作符两边必须是数字;使用"+"时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串。
使用内建的指令int获得整数部分:
${ 1.1?int }
${ 1.999?int }
${ -1.1?int }
${ -1.999?int }
结果:
2
1
1
-1
-1
比较操作符-<#if expression>...</#if>
1.)使用=(或==,完全相等)测试两个值是否相等,使用!= 测试两个值是否不相等
2.)=和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = "1">会引起错误
3.)Freemarker是精确比较,所以"x"、"x "和"X"是不相等的
4.)对数字和日期可以使用<、<=、>和>=,但不能用于字符串
5.) 由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免这种情况,例如<#if (x > y)>,另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>=
逻辑操作符-&&(and)、||(or)、!(not),只能用于布尔值,否则会产生错误
<#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>
内置函数-用法类似访问hash(散列)的子变量,只是使用"?"替代".",例如:user?upper_case
下面列出常用的一些函数:
对于字符串
html-对字符串进行HTML编码
cap_first-使字符串第一个字母大写
lower_case-将字符串转换成小写
trim-去掉字符串前后的空白字符
对于Sequences(序列)
size-获得序列中元素的数目
对于数字
int-取得数字的整数部分(如-1.9?int的结果是-1)
例一:
<
#--
test的值为Tom & Jerry --
>
${ test?html }
${ test?upper_case?html }
结果:
Tom & Jerry
TOM & JERRY
例二:
<
#--
seasons的值为"winter", "spring", "summer", "autumn" --
>
${ seasons?size }
${ seasons[1]?cap_first }
<
#--
left side can by any expression --
>
${ "horse"?cap_first }
结果:
4
Spring
Horse
方法的调用
${ repeat("What", 3) }
${ repeat(repeat("x", 2), 3) + repeat("What", 4)?upper_case }
结果:
WhatWhatWhat
xxxxxxWHATWHATWHATWHAT
操作符优先顺序
后缀 [subvarName] [subStringRange] . (methodParams)
一元 +expr、-expr、!
内建 ?
乘法 *、 / 、%
加法 +、-
关系 <、>、<=、>=(lt、lte、gt、gte)
相等 =、!=
逻辑 &&
逻辑 ||
数字范围 ..
三.) Interpolation:由${ ... }或#{ ... }两种类型,输出计算值,可以定义输出的格式
例一:
<
#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") }
结果:
yes
例四:
<
#--
x is 2.582 and y is 4 --
>
#{ x; M2 }
<
#--
2.58 --
>
#{ y; M2 }
<
#--
4 --
>
#{ x; m1 }
<
#--
2.6 --
>
#{ y; m1 }
<
#--
4.0 --
>
#{ x; m1M2 }
<
#--
2.58 --
>
#{ y; m1M2 }
<
#--
4.0 --
>
说明:mX-小数部分最小X位;MX-小数部分最大X位。
四.) 注释:<#--和-->
下面是一个常用的模板例子:
<
p
>
We have these animals:
<
table
border
=1>
<tr
><
th
>
Name
<
th
>
Price
<
#list
animals as being
>
<
tr
>
<
td
>
<
#if
being.size
= "large"
><
b
></
#if
>
${ being.name }
<
#if
being.size
="large"
></
b
></
#if
>
<
td
>
${ being.price } Euros
</
#list
>
</
table
>
<
#include
"/copyright_footer.html"
>
注意点:
1.) FreeMarker是区分大小写的;
2.) FTL标记不能位于另一个FTL标记内部,例如:<#if <#include 'foo'>='bar'>...</if>;
3.) ${ … }只能在文本中使用;
4.) 多余的空白字符会在模板输出时去除;
5.) 如果使用的指令不存在,会产生一个错误消息。
有两种不同的类型:Macro(宏)和transform(传递器),Macro是在模板中使用macro指令定义,而transform是在模板外由程序定义(基本上都是基于Java的),这里通过Macro来介绍自定义指令。
例一:
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
使用:<@greet>< /@greet> 或 <@greet/>
结果:<font size="+2">Hello Joe!</font>
参数-在macro指令中可以在宏变量之后定义参数
例二:
<#macro greet person>
<font size="+2">Hello ${person}!</font>
</#macro>
使用:<@greet person="Fred"/> and <@greet person="Batman"/>
结果: <font size="+2">Hello Fred!</font> and <font size="+2">Hello Batman!</font>
macro可以有多个参数,参数的次序是无关的,在macro指令中只能使用定义的参数,并且必须对所有参数赋值,可以在定义参数时指定缺省值:
<
#macro
greet person color
="black"
>
<
font
size
="+2"
color
="${color}"
>
Hello ${person}!
</
font
>
</
#macro
>
在自定义指令嵌套内容:模板片断中使用<#nested>指令
<
#macro
border
>
<
table
border
=4
cellspacing
=0
cellpadding
=4><tr><td>
<#nested
>
</
tr
></
td
></
table
>
</
#macro
>
使用:<@border>The bordered text</@border>
结果:
<
table
border
=4
cellspacing
=0
cellpadding
=4>
<tr
><
td
>
The bordered text
</
tr
></
td
></
table
>
<#nested>指令可以被多次调用:
<
#macro
do_thrice
>
<
#nested
>
<
#nested
>
<
#nested
>
</
#macro
>
使用:
<@do_thrice>Anything.</@do_thrice>
结果:
Anything.
Anything.
Anything.
注意:嵌套内容是无法访问到macro中的局部变量的。
例如:
<
#macro
repeat count
>
<
#local
y
= "test"
>
<
#list
1..count as x
>
${y} ${count}/${x}:
<
#nested
>
</
#list
>
</
#macro
>
<
@repeat
count
=3>${y?default("?")}
${x?default("?")} ${count?default("?")}</@repeat
>
结果:
test 3/1: ? ? ?
test 3/2: ? ? ?
test 3/3: ? ? ?
下面是一个嵌套使用自定义指令的例子:
<
@border
>
<
ul
>
<
@do_thrice
>
<
li
><
@greet
person
="Joe"
/>
</
@do_thrice
>
</
ul
>
</
@border
>
结果:
<
table
border
=4
cellspacing
=0
cellpadding
=4><tr><td>
<ul
>
<
li
><
font
size
="+2"
>
Hello Joe!
</
font
>
<
li
><
font
size
="+2"
>
Hello Joe!
</
font
>
<
li
><
font
size
="+2"
>
Hello Joe!
</
font
>
</
ul
>
</
tr
></
td
></
table
>
在macro中使用循环变量-作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字:
<
#macro
repeat count
>
<
#list
1..count as x
>
<
#nested
x, x/2, x
==count>
</#list
>
</
#macro
>
<
@repeat
count
=4
; c, halfc, last
>
${c}. ${halfc}
<
#if
last
>
Last!
</
#if
>
/
@repeat
结果:
1. 0.5
2. 1
3. 1.5
4. 2 Last!
注意:循环变量和用户定义指令开始标记指定的数目可以不同,调用时少指定循环变量,则多指定的值不可见,调用时多指定循环变量,多余的循环变量不会被创建。
模板中的变量,有三种类型:
1.) plain(全局)变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换
2.) 局部变量:在macro中有效,使用local指令创建和替换
3.) 循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量
用assign指令创建和替换的例子:
<
#assign
x
= 1>
<#-- create variable x --
>
${x}
<
#assign
x
= x
+ 3
>
<
#--
replace variable x --
>
${x}
结果:
1
4
局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:
<
#assign
x
= "plain"
>
1. ${x}
<
#--
we see the plain var. here --
>
<
@test
/>
6. ${x}
<
#--
the value of plain var. was not changed --
>
<
#list
["loop"] as x
>
7. ${x}
<
#--
now the loop var. hides the plain var. --
>
<
#assign
x
= "plain2"
>
<
#--
replace the plain var, hiding does not mater here --
>
8. ${x}
<
#--
it still hides the plain var. --
>
</
#list
>
9. ${x}
<
#--
the new value of plain var. --
>
<
#macro
test
>
2. ${x}
<
#--
we still see the plain var. here --
>
<
#local
x
= "local"
>
3. ${x}
<
#--
now the local var. hides it --
>
<
#list
["loop"] as x
>
4. ${x}
<
#--
now the loop var. hides the local var. --
>
</
#list
>
5. ${x}
<
#--
now we see the local var. again --
>
</
#macro
>
结果:
1. plain
2. plain
3. local
4. loop
5. local
6. plain
7. loop
8. loop
9. plain2
内部循环变量隐藏同名的外部循环变量,例如:
<
#list
["loop 1"] as x
>
${x}
<
#list
["loop 2"] as x
>
${x}
<
#list
["loop 3"] as x
>
${x}
</
#list
>
${x}
</
#list
>
${x}
</
#list
>
结果:
loop 1
loop 2
loop 3
loop 2
loop 1
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:
<
#assign
user
= "Joe Hider"
>
${user}
<
#--
prints: Joe Hider --
>
${.globals.user}
<
#--
prints: Big Joe --
>

802

被折叠的 条评论
为什么被折叠?



