学习FreeMarker

 
学习FreeMarker(一)

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获得整数部分

${ (x/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 &amp; Jerry
TOM &amp; 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 -- >   

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值