freemarker快速入门.docx
《freemarker快速入门.docx》由会员分享,可在线阅读,更多相关《freemarker快速入门.docx(27页珍藏版)》请在冰点文库上搜索。
freemarker快速入门
freemarker快速入门
1)模板+数据模型=输出
FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念他们是分工劳动的:
设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;
程序员创建系统,生成设计页面要显示的数据。
经常会遇到的问题是:
在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的。
在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码。
先来解释一下freemaker的基本语法了,
<#...>中存放所有freemaker的内容,之外的内容全部原样输出。
<@.../>是函数调用
两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。
freemaker提供的控制包括如下:
<#ifcondition><#elseifcondition><#else>条件判断
<#listhash_or_seqasvar>遍历hash表或者collection(freemaker称作sequence)的成员
<#macronameparam1param2...><#nestedparam>宏,无返回参数
<#functionnameparam1param2><#returnval>函数,有返回参数
var?
member_function(...)用函数对var进行转换,freemaker称为build-ins。
实际内部实现类似member_function(var,...)
stringA[M..N]取子字符串,类似substring(stringA,M,N)
{key:
value,key2:
value2...}直接定义一个hash表
[item0,item1,item2...]直接定义一个序列
hash0[key0]存取hash表中key对应的元素
seq0[5]存取序列指定下标的元素
<@function1param0param1.../>调用函数function1
<@macro0param0param1;nest_param0nest_param1...>nest_body@macro>调用宏,并处理宏的嵌套
<#assignvar=value>定义变量并初始化
<#localvar=value>在macro或者function中定义局部变量并初始化
<#globalvar=value>定义全局变量并初始化
${var}输出并替换为表达式的值
<#visitxmlnode>调用macro匹配xmlnode本身及其子节点
<#recursexmlnode>调用macro匹配xmlnode的子节点
下面是一个例子:
Welcome!Welcome${user}!
Ourlatestproduct:
${latestProduct.name}!
这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)。
至于user、latestProduct.url和latestProduct.name来自于数据模型(datamodel)。
数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。
模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。
下面是一个可能的数据模型:
(root)
|
+-user="BigJoe"
|
+-latestProduct
|
+-url="products/greenmouse.html"
|
+-name="greenmouse"
数据模型类似于计算机的文件系统,latestProduct可以看作是目录。
2、数据模型
(1)基础
在快速入门中介绍了在模板中使用的三种基本对象类型:
scalars、hashes和sequences,其实还可以有其它更多的能力:
∙scalars:
存储单值
∙hashes:
充当其它对象的容器,每个都关联一个唯一的查询名字
∙sequences:
充当其它对象的容器,按次序访问
∙方法:
通过传递的参数进行计算,以新对象返回结果
∙用户自定义FTL标记:
宏和变换器
通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子:
(root)
|
+-mouse="Yerri"
|
+-age=12
|
+-color="brown">
mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板:
${mouse}<#--usemouseasscalar-->
${mouse.age}<#--usemouseashash-->
${mouse.color}<#--usemouseashash-->
输出结果是:
Yerri
12
brown
(2)Scalar变量
Scalar变量存储单值,可以是:
∙字符串:
简单文本,在模板中使用引号(单引号或双引号)括起
∙数字:
在模板中直接使用数字值
∙日期:
存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们
∙布尔值:
true或false,通常在<#if…>标记中使用
(3)hashes、sequences和集合
有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:
∙hashes:
具有一个唯一的查询名字和它包含的每个变量相关联
∙sequences:
使用数字和它包含的每个变量相关联,索引值从0开始
集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list…>指令使用的受限sequences
(4)方法
方法变量通常是基于给出的参数计算值。
下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值:
Theaverageof3and5is:
${avg(3,5)}
Theaverageof6and10and20is:
${avg(6,10,20)}
Theaverageofthepriceofpythonandelephantis:
${avg(animals.python.price,animals.elephant.price)}
(5)宏和变换器
宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性
(6)节点
节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲
3、模板
(1)整体结构
模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:
∙文本:
直接输出
∙Interpolation:
由${和},或#{和}来限定,计算值替代输出
∙FTL标记:
FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出
∙注释:
由<#--和-->限定,不会输出
下面是以一个具体模板例子:
Welcome!<#--Greettheuserwithhis/hername-->
Welcome${user}!
Wehavetheseanimals:
<#listanimalsasbeing>
- ${being.name}for${being.price}Euros
#list>
注意事项:
∙FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的
∙Interpolation只能在文本中使用
∙FTL标记不能位于另一个FTL标记内部,例如:
<#if<#include'foo'>='bar'>...
∙注释可以位于FTL标记和Interpolation内部,如下面的例子:
Welcome${user<#--Thenameofuser-->}!
Wehavetheseanimals:
<#list<#--somecomment...-->animalsas<#--again...-->being>
...
∙余的空白字符会在模板输出时移除
(2)指令
在FreeMarker中,使用FTL标记引用指令。
有三种FTL标记,这和HTML标记是类似的:
∙开始标记:
<#directivenameparameters>
∙结束标记:
#directivename>
∙空内容指令标记:
<#directivenameparameters/>
有两种类型的指令:
预定义指令和用户定义指令。
用户定义指令要使用@替换#,如<@mydirective>...@mydirective>(会在后面讲述)。
FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:
<#listanimalsasbeing>
- ${being.name}for${being.price}Euros
<#ifuse="BigJoe">
(exceptforyou)
#list>
#if><#--WRONG!
-->
如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。
FreeMarker会忽略FTL标记中的空白字符,如下面的例子:
<#list
animalsas
being
>
${being.name}for${being.price}Euros
#list>
但是,<、和指令之间不允许有空白字符。
(3)表达式
直接指定值
∙字符串
使用单引号或双引号限定
如果包含特殊字符需要转义,如下面的例子:
${"It's\"quoted\"and
thisisabackslash:
\\"}
${'It\'s"quoted"and
thisisabackslash:
\\'}
输出结果是:
It's"quoted"and
thisisabackslash:
\
It's"quoted"and
thisisabackslash:
\
下面是支持的转义序列:
转义序列
含义
\"
双引号(u0022)
\'
单引号(u0027)
反斜杠(u005C)
\n
换行(u000A)
\r
Return(u000D)
\t
Tab(u0009)
\b
Backspace(u0008)
\f
Formfeed(u000C)
\l
<
\g
>
\a
&
\{
{
\xCode
4位16进制Unicode代码
有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:
${r"${foo}"}
${r"C:
\foo\bar"}
输出的结果是:
${foo}
C:
\foo\bar
∙数字
直接输入,不需要引号
精度数字使用“.”分隔,不能使用分组符号
目前版本不支持科学计数法,所以“1E3”是错误的
不能省略小数点前面的0,所以“.5”是错误的
数字8、+8、08和8.00都是相同的
∙布尔值
true和false,不使用引号
∙序列
由逗号分隔的子变量列表,由方括号限定,下面是一个例子:
<#list["winter","spring","summer","autumn"]asx>
${x}
#list>
输出的结果是:
winter
spring
summer
autumn
列表的项目是表达式,所以可以有下面的例子:
[2+2,[1,2,3,4],"whatnot"]
可以使用数字范围定义数字序列,例如2..5等同于[2,3,4,5],但是更有效率,注意数字范围没有方括号
可以定义反递增的数字范围,如5..2
∙散列(hash)
由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子:
{"name":
"greenmouse","price":
150}
键和值都是表达式,但是键必须是字符串
获取变量
∙顶层变量:
${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头
∙从散列中获取数据
可以使用点语法或方括号语法,假设有下面的数据模型:
(root)
|
+-book
||
|+-title="Breedinggreenmouses"
||
|+-author
||
|+-name="JuliaSmith"
||
|+-info="Biologist,1923-1985,Canada"
|
+-test="title"
下面都是等价的:
book.author.name
book["author"].name
book.author.["name"]
book["author"]["name"]
使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果
∙从序列获得数据:
和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:
第一个项目的索引是0
序列片断:
使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式
∙特殊变量:
FreeMarker内定义变量,使用.variablename语法访问
字符串操作
∙Interpolation(或连接操作)
可以使用${..}(或#{..})在文本部分插入表达式的值,例如:
${"Hello${user}!
"}
${"${user}${user}${user}${user}"}
可以使用+操作符获得同样的结果
${"Hello"+user+"!
"}
${user+user+user+user}
${..}只能用于文本部分,下面的代码是错误的:
<#if${isBig}>Wow!
#if>
<#if"${isBig}">Wow!
#if>
应该写成:
<#ifisBig>Wow!
#if>
∙子串
例子(假设user的值为“BigJoe”):
${user[0]}${user[4]}
${user[1..4]}
结果是(注意第一个字符的索引是0):
BJ
igJ
序列操作
∙连接操作:
和字符串一样,使用+,下面是一个例子:
<#list["Joe","Fred"]+["Julia","Kate"]asuser>
-${user}
#list>
输出结果是:
-Joe
-Fred
-Julia
-Kate
散列操作
∙连接操作:
和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如:
<#assignages={"Joe":
23,"Fred":
25}+{"Joe":
30,"Julia":
18}>
-Joeis${ages.Joe}
-Fredis${ages.Fred}
-Juliais${ages.Julia}
输出结果是:
-Joeis30
-Fredis25
-Juliais18
算术运算
∙+、-、×、/、%,下面是一个例子:
${x*x-100}
${x/2}
${12%10}
输出结果是(假设x为5):
-75
2.5
2
操作符两边必须是数字,因此下面的代码是错误的:
${3*"5"}<#--WRONG!
-->
使用+操作符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串,例如:
${3+"5"}
输出结果是:
35
使用内建的int(后面讲述)获得整数部分,例如:
${(x/2)?
int}
${1.1?
int}
${1.999?
int}
${-1.1?
int}
${-1.999?
int}
输出结果是(假设x为5):
2
1
1
-1
-1
∙比较操作符
使用=(或==,完全相等)测试两个值是否相等,使用!
=测试两个值是否不相等
=和!
=两边必须是相同类型的值,否则会产生错误,例如<#if1="1">会引起错误
Freemarker是精确比较,所以对"x"、"x"和"X"是不相等的
对数字和日期可以使用<、<=、>和>=,但不能用于字符串
由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免这种情况,例如<#if(x>y)>
另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>=
∙逻辑操作符
&&(and)、||(or)、!
(not),只能用于布尔值,否则会产生错误
例子:
<#ifx<12&&color="green">
Wehavelessthan12things,andtheyaregreen.
#if>
<#if!
hot><#--herehotmustbeaboolean-->
It'snothot.
#if>
∙内建函数
内建函数的用法类似访问散列的子变量,只是使用“?
”替代“.”,下面列出常用的一些函数
∙
o字符串使用的:
html:
对字符串进行HTML编码
cap_first:
使字符串第一个字母大写
lower_case:
将字符串转换成小写
upper_case:
将字符串转换成大写
trim:
去掉字符串前后的空白字符
∙
o序列使用的:
size:
获得序列中元素的数目
∙
o数字使用的:
int:
取得数字的整数部分(如-1.9?
int的结果是-1)
例子(假设test保存字符串"Tom&Jerry"):
${test?
html}
${test?
upper_case?
html}
输出结果是:
Tom&Jerry
TOM&JERRY
∙操作符优先顺序
操作符组
操作符
后缀
[subvarName][subStringRange].(methodParams)
一元
+expr、-expr、!
内建
?
乘法
*、/、%
加法
+、-
关系
<、>、<=、>=(lt、lte、gt、gte)
相等
==(=)、!
=
逻辑and
&&
逻辑or
双竖线
数字范围
..
(4)Interpolation
Interpolation有两种类型:
1.通用Interpolation:
${expr}
1.数字Interpolation:
#{expr}或#{expr;format}
注意:
Interpolation只能用于文本部分
∙通用Interpolation
插入字符串值:
直接输出表达式结果
插入数字值:
根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:
<#settingnumber_format="currency"/>
<#assignanswer=42/>
${answer}
${answer?
string}<#--thesameas${answer}-->
${answer?
string.number}
${answer?
string.currency}
${answer?
string.percent}
输出结果是:
$42.00
$42.00
42
$42.00
4,200%
插入日期值:
根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子:
${lastUpdated?
string("yyyy-MM-ddHH:
mm:
sszzzz")}
${lastUpdated?
string("EEE,MMMd,''yy")}
${lastUpdated?
string("EEEE,MMMMdd,yyyy,hh:
mm:
ssa'('zzz')'")}
输出的结果类似下面的格式:
2003-04-0821:
24:
44PacificDaylightTime
Tue,Apr8,'03
Tuesday,April08,2003,09:
24:
44PM(PDT)
插入布尔值:
根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:
<#assignfoo=true/>
${foo?
string("yes","no")}
输出结果是:
yes
∙数字Interpolation的#{expr;format}形式可以用来格式化数字,format可以是:
mX:
小数部分最小X位
MX:
小数部分最大X位
例子:
<#--IfthelanguageisUSEnglishtheoutputis:
-->
<#assignx=2.582/>
<#assigny=4/>
#{x;M2}<#--2.58-->
#{y;M2}<#--4-->
#{x;m1}<#--2.6-->
#{y;m1}<#--4.0-->
#{x;m1M2}<#--2.58-->
#