FreeMarkerZ设计者和E序员是h不同专业技能的不同个体的观念他们是分工力_的:
设计者专注于表示——创建HTML文g、图片、Web面的其它可视化斚wQ?br />
E序员创建系l,生成设计面要显C的数据?br />
l常会遇到的问题是:在Web面Q或其它cd的文档)中显C的信息在设计页面时是无效的Q是Z动态数据的。在q里Q你可以在HTMLQ或其它要输出的文本Q中加入一些特定指令,FreeMarker会在输出面l最l用hQ用适当的数据替代这些代码?/p>
先来解释一下freemaker的基本语法了Q?br />
<# ... > 中存放所有freemaker的内容,之外的内容全部原栯出?br />
<@ ... /> 是函数调?br />
两个定界W内的内容中Q第一个符可C指令或者函数名Q其后的跟随参数。freemaker提供的控制包括如下:
<#if condition><#elseif condition><#else> 条g判断
<#list hash_or_seq as var> 遍历hash表或者collectionQfreemakerUCsequenceQ的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参?br />
<#function name param1 param2><#return val>函数Q有q回参数
var?member_function(...) 用函数对varq行转换QfreemakerUCؓbuild-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符ԌcMsubstring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash?br />
[item0, item1, item2 ...] 直接定义一个序?br />
hash0[key0] 存取hash表中key对应的元?br />
seq0[5] 存取序列指定下标的元?br />
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body </@macro> 调用宏,q处理宏的嵌?br />
<#assign var = value > 定义变量q初始化
<#local var = value> ?macro 或?function 中定义局部变量ƈ初始?br />
<#global var = value > 定义全局变量q初始化
${var} 输出q替换ؓ表达式的?br />
<#visit xmlnode> 调用macro匚wxmlnode本n及其子节?br />
<#recurse xmlnode> 调用macro匚wxmlnode的子节点
下面是一个例子:
<html>q个例子是在单的HTML中加入了一些由${…}包围的特定代码,q些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文gq为模板(TemplateQ?br /> 至于user、latestProduct.url和latestProduct.name来自于数据模型(data modelQ?br /> 数据模型q序员~程来创建,向模板提供变化的信息Q这些信息来自于数据库、文Ӟ甚至于在E序中直接生成?br /> 模板设计者不兛_数据从那儿来Q只知道使用已经建立的数据模型?br />
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
下面是一个可能的数据模型Q?
(root)数据模型cM于计机的文件系l,latestProduct可以看作是目录?
|
+- user = "Big Joe"
|
+- latestProduct
|
+- url = "products/greenmouse.html"
|
+- name = "green mouse"
在快速入门中介绍了在模板中用的三种基本对象cdQscalars、hashes 和sequencesQ其实还可以有其它更多的能力Q?
通常每个变量只具有上q的一U能力,但一个变量可以具有多个上q能力,如下面的例子Q?
(root)mouse既是scalars又是hashesQ将上面的数据模型合q到下面的模板:
|
+- mouse = "Yerri"
|
+- age = 12
|
+- color = "brown">
${mouse} <#-- use mouse as scalar -->输出l果是:
${mouse.age} <#-- use mouse as hash -->
${mouse.color} <#-- use mouse as hash -->
Yerri
12
brown
Scalar变量存储单|可以是:
有些变量不包含Q何可昄的内容,而是作ؓ容器包含其它变量Q者有两种cdQ?
集合变量通常cMsequencesQ除非无法访问它的大和不能使用索引来获得它的子变量Q集合可以看作只能由<#list …>指o使用的受限sequences
Ҏ变量通常是基于给出的参数计算倹{?
下面的例子假讄序员已经方法变量avg攑ֈ数据模型中,用来计算数字q_|
The average of 3 and 5 is: ${avg(3, 5)}
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
The average of the price of python and elephant is:
${avg(animals.python.price, animals.elephant.price)}
宏和变换器变量是用户自定义指令(自定义FTL标记Q,会在后面讲述q些高Ҏ?
节点变量表示为树型结构中的一个节点,通常在XML处理中用,会在后面的专门章节中?
模板使用FTLQFreeMarker模板语言Q编写,是下面各部分的一个组合:
下面是以一个具体模板例子:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<#-- Greet the user with his/her name -->
<h1>Welcome ${user}!</h1>
<p>We have these animals:
<ul>
<#list animals as being>
<li>${being.name} for ${being.price} Euros
</#list>
</ul>
</body>
</html>
注意事项Q?
<#if <#include 'foo'>='bar'>...</if>
<h1>Welcome ${user <#-- The name of user -->}!</h1>
<p>We have these animals:
<ul>
<#list <#-- some comment... --> animals as <#-- again... --> being>
...
在FreeMarker中,使用FTL标记引用指o。有三种FTL标记Q这和HTML标记是类似的Q?
有两U类型的指oQ预定义指o和用户定义指令?
用户定义指o要用@替换#Q如<@mydirective>...</@mydirective>Q会在后面讲qͼ?
FTL标记不能够交叉,而应该正的嵌套Q如下面的代码是错误的:
<ul>如果使用不存在的指oQFreeMarker不会使用模板输出Q而是产生一个错误消息?
<#list animals as being>
<li>${being.name} for ${being.price} Euros
<#if use = "Big Joe">
(except for you)
</#list>
</#if> <#-- WRONG! -->
</ul>
FreeMarker会忽略FTL标记中的I白字符Q如下面的例子:
<#list但是Q?lt;?lt;/和指令之间不允许有空白字W?
animals as
being
>
${being.name} for ${being.price} Euros
</#list >
直接指定?/strong>
如果包含Ҏ字符需要{义,如下面的例子Q?
${"It's \"quoted\" and输出l果是:
this is a backslash: \\"}
${'It\'s "quoted" and
this is a backslash: \\'}
It's "quoted" and下面是支持的转义序列Q?
this is a backslash: \
It's "quoted" and
this is a backslash: \
转义序列 | 含义 |
---|---|
\" | 双引?u0022) |
\' | 单引?u0027) |
反斜?u005C) | |
\n | 换行(u000A) |
\r | Return (u000D) |
\t | Tab (u0009) |
\b | Backspace (u0008) |
\f | Form feed (u000C) |
\l | < |
\g | > |
\a | & |
\{ | { |
\xCode | 4?6q制Unicode代码 |
有一cȝD的字符串称为raw字符Ԍ被认为是U文本,其中的\和{{不hҎ含义Q该cdW串在引号前面加rQ下面是一个例子:
${r"${foo}"}输出的结果是Q?
${r"C:\foo\bar"}
${foo}
C:\foo\bar
直接输入Q不需要引?
_ֺ数字使用“.”分隔Q不能用分l符?
目前版本不支持科学计数法Q所?#8220;1E3”是错误的
不能省略数点前面的0Q所?#8220;.5”是错误的
数字8?8?8?.00都是相同?
true和falseQ不使用引号
由逗号分隔的子变量列表Q由Ҏ号限定,下面是一个例子:
<#list ["winter", "spring", "summer", "autumn"] as x>输出的结果是Q?
${x}
</#list>
winter列表的项目是表达式,所以可以有下面的例子:
spring
summer
autumn
[2 + 2, [1, 2, 3, 4], "whatnot"]可以使用数字范围定义数字序列Q例?..5{同于[2, 3, 4, 5]Q但是更有效率,注意数字范围没有Ҏ?
可以定义反递增的数字范_?..2
{"name":"green mouse", "price":150}键和值都是表辑ּQ但是键必须是字W串
获取变量
可以使用点语法或Ҏ可法,假设有下面的数据模型Q?
(root)下面都是{h的:
|
+- book
| |
| +- title = "Breeding green mouses"
| |
| +- author
| |
| +- name = "Julia Smith"
| |
| +- info = "Biologist, 1923-1985, Canada"
|
+- test = "title"
book.author.name使用点语法,变量名字有顶层变量一L限制Q但Ҏ可法没有该限制Q因为名字是L表达式的l果
book["author"].name
book.author.["name"]
book["author"]["name"]
序列片断Q用[startIndex..endIndex]语法Q从序列中获得序列片断(也是序列Q;startIndex和endIndex是结果ؓ数字的表辑ּ
字符串操?
可以使用${..}Q或#{..}Q在文本部分插入表达式的|例如Q?
${"Hello ${user}!"}可以使用+操作W获得同Ll果
${"${user}${user}${user}${user}"}
${"Hello " + user + "!"}${..}只能用于文本部分Q下面的代码是错误的Q?
${user + user + user + user}
<#if ${isBig}>Wow!</#if>应该写成Q?
<#if "${isBig}">Wow!</#if>
<#if isBig>Wow!</#if>
例子Q假设user的gؓ“Big Joe”Q:
${user[0]}${user[4]}l果是(注意W一个字W的索引?Q:
${user[1..4]}
BJ序列操作
ig J
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>输出l果是:
- ${user}
</#list>
- Joe散列操作
- Fred
- Julia
- Kate
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>输出l果是:
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
- Joe is 30术q算
- Fred is 25
- Julia is 18
${x * x - 100}输出l果是(假设x?Q:
${x / 2}
${12 % 10}
-75操作W两边必L数字Q因此下面的代码是错误的Q?
2.5
2
${3 * "5"} <#-- WRONG! -->使用+操作W时Q如果一Ҏ数字Q一Ҏ字符Ԍ׃自动数字{换ؓ字符Ԍ例如Q?
${3 + "5"}输出l果是:
35使用内徏的intQ后面讲qͼ获得整数部分Q例如:
${(x/2)?int}输出l果是(假设x?Q:
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}
2
1
1
-1
-1
使用=Q或==Q完全相{)试两个值是否相{,使用!= 试两个值是否不相等
=?=两边必须是相同类型的|否则会生错误,例如<#if 1 = "1">会引起错?
Freemarker是精比较,所以对"x"?x "?X"是不相等?
Ҏ字和日期可以使用<?lt;=?gt;?gt;=Q但不能用于字符?
׃Freemarker会将>解释成FTL标记的结束字W,所以对?gt;?gt;=可以使用括号来避免这U情况,例如<#if (x > y)>
另一U替代的Ҏ是,使用lt、lte、gt和gte来替?lt;?lt;=?gt;?gt;=
&&QandQ、||QorQ?QnotQ,只能用于布尔|否则会生错?
例子Q?
<#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>
内徏函数的用法类D问散列的子变量,只是使用“?”替代“.”Q下面列出常用的一些函?
htmlQ对字符串进行HTML~码
cap_firstQ字符串第一个字母大?
lower_caseQ将字符串{换成写
upper_caseQ将字符串{换成大写
trimQ去掉字W串前后的空白字W?
sizeQ获得序列中元素的数?
intQ取得数字的整数部分Q如-1.9?int的结果是-1Q?
例子Q假设test保存字符?Tom & Jerry"Q:
${test?html}输出l果是:
${test?upper_case?html}
Tom & Jerry
TOM & JERRY
操作W组 | 操作W? |
---|---|
后缀 | [subvarName] [subStringRange] . (methodParams) |
一? | +expr?expr? |
内徏 | ? |
乘法 | *?/ ? |
加法 | +? |
关系 | <?gt;?lt;=?gt;=Qlt、lte、gt、gteQ? |
相等 | ==Q?Q?= |
逻辑and | && |
逻辑or | 双竖U?/td> |
数字范围 | .. |
Interpolation有两U类型:
注意QInterpolation只能用于文本部分
插入字符串|直接输出表达式结?
插入数字|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个例子:
<#setting number_format="currency"/>输出l果是:
<#assign answer=42/>
${answer}
${answer?string} <#-- the same as ${answer} -->
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
$42.00插入日期|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个用格式模式的例子Q?
$42.00
42
$42.00
4,200%
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}输出的结果类g面的格式Q?
${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插入布尔|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个例子:
Tue, Apr 8, '03
Tuesday, April 08, 2003, 09:24:44 PM (PDT)
<#assign foo=true/>输出l果是:
${foo?string("yes", "no")}
yes
mXQ小数部分最X?
MXQ小数部分最大X?
例子Q?
<#-- 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 -->
宏和变换器变量是两种不同cd的用户定义指令,它们之间的区别是宏是在模板中使用macro指o定义Q而变换器是在模板外由E序定义Q这里只介绍?
宏是和某个变量关联的模板片断Q以便在模板中通过用户定义指o使用该变量,下面是一个例子:
<#macro greet>作ؓ用户定义指o使用宏变量时Q用@替代FTL标记中的#
<font size="+2">Hello Joe!</font>
</#macro>
<@greet></@greet>如果没有体内容,也可以用:
<@greet/>
在macro指o中可以在宏变量之后定义参敎ͼ如:
<#macro greet person>可以q样使用q个宏变量:
<font size="+2">Hello ${person}!</font>
</#macro>
<@greet person="Fred"/> and <@greet person="Batman"/>输出l果是:
<font size="+2">Hello Fred!</font>
and <font size="+2">Hello Batman!</font>
宏的参数是FTL表达式,所以下面的代码h不同的意思:
<@greet person=Fred/>q意味着Fred变量的glperson参数Q该g仅是字符Ԍq可以是其它cdQ甚x复杂的表辑ּ
可以有多参数Q下面是一个例子:
<#macro greet person color>可以q样使用该宏变量Q?
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
<@greet person="Fred" color="black"/>其中参数的次序是无关的,因此下面是等LQ?
<@greet color="black" person="Fred"/>只能使用在macro指o中定义的参数Qƈ且对所有参数赋|所以下面的代码是错误的Q?
<@greet person="Fred" color="black" background="green"/>可以在定义参数时指定~省|如:
<@greet person="Fred"/>
<#macro greet person color="black">q样<@greet person="Fred"/>正了
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
宏的参数是局部变量,只能在宏定义中有?
用户定义指o可以有嵌套内容,使用<#nested>指o执行指o开始和l束标记之间的模板片?
例子Q?
<#macro border>q样使用该宏变量Q?
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</tr></td></table>
</#macro>
<@border>The bordered text</@border>输出l果Q?
<table border=4 cellspacing=0 cellpadding=4><tr><td>
The bordered text
</tr></td></table>
<#nested>指o可以被多ơ调用,例如Q?
<#macro do_thrice>输出l果Q?
<#nested>
<#nested>
<#nested>
</#macro>
<@do_thrice>
Anything.
</@do_thrice>
Anything.嵌套内容可以是有效的FTLQ下面是一个有些复杂的例子Q?<@border> <ul> <@do_thrice> <li><@greet person="Joe"/> </@do_thrice> </ul> </@border> }}} 输出l果Q?
Anything.
Anything.
<table border=4 cellspacing=0 cellpadding=4><tr><td>宏定义中的局部变量对嵌套内容是不可见的,例如Q?
<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 repeat count>输出l果Q?
<#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: ? ? ?
用户定义指o可以有@环变量,通常用于重复嵌套内容Q基本用法是Q作为nested指o的参C递@环变量的实际|而在调用用户定义指oӞ?lt;@…>开始标记的参数后面指定循环变量的名?
例子Q?
<#macro repeat count>输出l果Q?
<#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!
指定的@环变量的数目和用户定义指令开始标记指定的不同不会有问?
调用时少指定循环变量Q则多指定的g可见
调用时多指定循环变量Q多余的循环变量不会被创?
在模板中定义的变量有三种cdQ?
宏的参数是局部变量,而不是@环变量;局部变量隐藏(而不是覆盖)同名的plain变量Q@环变量隐藏同名的局部变量和plain变量Q下面是一个例子:
<#assign x = "plain">输出l果Q?
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>输出l果Q?
${x}
<#list ["loop 2"] as x>
${x}
<#list ["loop 3"] as x>
${x}
</#list>
${x}
</#list>
${x}
</#list>
loop 1模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用Ҏ变量globalQ下面的例子假设数据模型中的user的值是Big JoeQ?
loop 2
loop 3
loop 2
loop 1
<#assign user = "Joe Hider">
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->
通常情况Q只使用一个名字空_UCؓd字空?
Z创徏可重用的宏、变换器或其它变量的集合Q通常U库Q,必须使用多名字空_其目的是防止同名冲突
下面是一个创建库的例子(假设保存在lib/my_test.ftl中)Q?
<#macro copyright date>使用import指o导入库到模板中,Freemarker会ؓ导入的库创徏新的名字I间Qƈ可以通过import指o中指定的散列变量讉K库中的变量:
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "jsmith@acme.com">
<#import "/lib/my_test.ftl" as my>输出l果Q?
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.可以看到例子中用的两个同名变量q没有冲H,因ؓ它们位于不同的名字空?
<br>Email: jsmith@acme.com</p>
jsmith@acme.com
fred@acme.com
可以使用assign指o在导入的名字I间中创建或替代变量Q下面是一个例子:
<#import "/lib/my_test.ftl" as my>输出l果Q?
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}
jsmith@acme.com数据模型中的变量M地方都可见,也包括不同的名字I间Q下面是修改的库Q?
jsmith@other.com
<#macro copyright date>假设数据模型中的user变量的值是FredQ则下面的代码:
<p>Copyright (C) ${date} ${user}. All rights reserved.</p>
</#macro>
<#assign mail = "${user}@acme.com">
<#import "/lib/my_test.ftl" as my>输出l果Q?
<@my.copyright date="1999-2002"/>
${my.mail}
<p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
Fred@acme.com
补充Q静态方法的调用Q:
Ҏ1Q?/strong>
##定义配置文g freemarkerstatic.properties
_Validator=com.longyou.util.Validator
_Functions=com.longyou.util.Functions
_EscapeUtils=com.longyou.util.EscapeUtils
/调用代码
${_Functions.toUpperCase("Hello")}<br>
${_EscapeUtils.escape("狼的原野")}
Ҏ2Q?/strong>
${stack.findValue("@package.ClassName@method")}
补充Q常用语?/strong>
EG.一个对象BOOK
1.输出 ${book.name}
I值判断:${book.name?if_exists },
${book.name?default(‘xxx’)}//默认值xxx
${ book.name!"xxx"}//默认值xxx
日期格式Q?{book.date?string('yyyy-MM-dd')}
数字格式Q?{book?string.number}--20
${book?string.currency}--<#-- $20.00 -->
${book?string.percent}?lt;#-- 20% -->
插入布尔|
<#assign foo=ture />
${foo?string("yes","no")} <#-- yes -->
2Q逻辑判断
a:
<#if condition>...
<#elseif condition2>...
<#elseif condition3>......
<#else>...
其中I值判断可以写?lt;#if book.name?? >
b:
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
3Q@环读?/p>
<#list sequence as item>
...
I值判?lt;#if bookList?size = 0>
e.g.
<#list employees as e>
${e_index}. ${e.name}
输出:
1. Readonly
2. Robbin
freemarker的Eclipse插g