,先来一打小白兔;
3.1 总体结构
用程序语言编写的程序就是模板,模板也被成为FTL(代表FreeMarker模板语言)。
模板是由如下部分混合而成的:
- Text文本:文本会照着原样来输出;
- Interpolation插值:这部分的输出会被计算的值来代替。插值由${和}所分隔(或者#{和},这种风格已经不建议再使用了)。
- FTL tags标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示,而且不会打印在输出内容中。
- Comments注释:FTL的注释和HTML的注释也很相似,但是它们是由<#–和–>来分隔的。注释会被FreeMarker所忽略,更不会在输出内容中显示。
FTL区分大小写;
FTL标签不可以在其他FTL标签和插值中使用,下面这样写是错的;
<#if <#include 'foo'>='bar'>...</#if>
注释可以放在FTL标签和插值中间;
3.2 指令
标签分为两种:
- 开始标签:<#directivename parametes>
- 结束标签:
指令有两种类型:预定义指令和用户自定义指令。对于用户自定义的指令使用@来代替#;
3.3 表达式
3.3.1 简介
${expression}
3.3.2 快速浏览(备忘单)
这里是给已经了解FreeMarker的人或有经验的程序员的一个提醒:
3.3.3 直接确定值
3.3.3.1 字符串
转义
${"It's \"quoted\" and this is a blackslash: \\"}
输出:
It's "quoted" and this is a blackslash: \
转义序列表:
在1-4位的16进制码。下面这个示例中都是在字符串中放置版权符号“\xA9 1999-2001”,“\x0A9 1999-2001”,“\x00A9 1999-2001”;
一种特殊的字符串就是原生字符串。在原生字符串中,反斜杠和${没有特殊的含义,它们被视为普通的字符。为了表明字符串是原生字符串,在开始的引号或单引号之前放置字母r;
${r"${foo}"}
${r"C:\foo\bar"}
将会打印:
${foo}
C:\foo\bar
实例
<ul>
<li>转义:${"It's \"quoted\" and this is a blackslash: \\"}</li>
<li>版权符号:${"\xA9 1999-2000"}</li>
<li>原生字符串:${r"${foo}"}</li>
</ul>
输出:
3.3.3.2 数字
科学记数法暂不支持使用(1E3就是错误的)。不能在小数点之前不写0(.5也是错误的);
3.3.3.3 布尔值
直接写true或false就表示一个布尔值了;
3.3.3.4 序列
指定一个文字的序列,使用逗号来分隔其中的每个子变量,然后把整个列表放到方括号中。
<#list ["winter", "spring", "summer", "autumn"] as x>
${x}
</#list>
将会打印出:
winter
spring
summer
autumn
列表中的项目是表达式,那么也可以这样做:[2+2, [1,2,3,4], “whatnot”],其中第一个子变量是数字4,第二个子变量是一个序列,第三个子变量是字符串“whatnot”。
也可以用start..end定义存储数字范围的序列,这里start和end是处理数字值表达式,比如2..5和[2, 3, 4, 5]是相同的,但是使用前者会更有效率(内存占用少而且速度快)。可以看出前者也没有使用方括号,这样也可以用来定义递减的数字范围,比如5..2。(此外,还可以省略end,只需5..即可,到无穷大)。
实例
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/3/list.ftl
<#assign season=["summer", "winter", "spring", "autumn"]>
<p>
<#list season as s>
${s},
</#list>
</p>
<p>
<#list season[2..] as x>
${x},
</#list>
</p>
输出:
summer, winter, spring, autumn,
spring, autumn,
3.3.3.5 哈希表
键和值成对出现并以冒号分隔。{“name”:“green mouse”,“price”:150};
3.3.4 检索变量
3.3.4.1 顶层变量
3.3.4.2 从哈希表中检索数据
book.author.name来读取到auther的name;
如果我们想指定同一个表达式的子变量,那么还有另外一种语法格式:book[“title”]。
下面这些示例它们含义都是相等的:book.author.name, book["author"].name, book.author.["name"], book["author"]["name"]
。
当使用点式语法时,顶层变量名的命名也是相同的限制(命名时只能使用字母,数字,下划线,$,@等),而使用方括号语法形式时就没有这样的限制,它可以是任意的表达式。(为了FreeMarker支持XML,如果变量名是*(星号)或者**,那么就应该使用方括号语法格式)。
3.3.4.3 从序列中检索数据
animals[0].name
3.3.4.4 特殊变量
特殊变量是由FreeMarker引擎本身定义的,为了使用它们,可以按照如下语法形式来进行:.variable_name;
3.3.5 字符串操作
3.3.5.1 插值(或连接)
3.3.5.2 获取一个字符
user[0],假设user是”Big Joe“,那么
${user[0]}
${user[4]}
将会打印:
B
J
可以使用切分序列的方式来获取一定范围内的字符,比如user[1..4]和{user[4..]},然而这种使用方法已经被废弃了,作为它的替代,可以使用内建函数substring。
实例
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/3/string.ftl
<ul>
<li>读取一个字符:${user[0]}</li>
<li>读取一定范围的字符:${user[1..5]}</li>
<li>这种操作已经废弃了,现在使用内建函数substring,${user?substring(1, 5)}</li>
</ul>
输出:
•读取一个字符:B
•读取一定范围的字符:ig Jo
•这种操作已经废弃了,现在使用内建函数substring,ig J
3.3.6 序列操作
3.3.6.1 连接
序列的连接可以使用+号来进行:
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
\- ${user}
</#list>
要注意不要在很多重复连接时使用序列连接操作,比如在循环中往序列上追加项目,通过这种方式进行的许多重复连接最终产生的序列读取的速度会变慢;
3.3.6.2 序列切分
使用[firstindex..lastindex]可以获取序列中的一部分,这里的firstindex和lastindex表达式的结果是数字,如果seq存储序列“a”,“b”,“c”,“d”,“f”,那么表达式seq[1..4]将会是含有“b”,“c”,“d”,“e”的序列。
实例
/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/3/list.ftl
<h3>序列的操作</h3>
<ul>
<li>+连接:
<#list ["sumer", "winter"]+["spring", "autumn"] as x>
${x}.
</#list>
</li>
<li>序列切分:
<#list season[2..3] as x>
${x},
</#list>
</li>
</ul>
3.3.7 哈希表操作
3.3.7.1 连接
可以使用+号连接哈希表
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
3.3.8 算数运算
求模(求余): %
3.3.9 比较运算
测试两个值相等使用=(或者==,二者是完全等同的)
3.3.10 逻辑操作
3.3.11 内建函数
内建函数以?形式提供变量的不同形式或者其他信息。
例如得到字符串的大写形式:user?upper_case;
字符串使用的内建函数:
- html:字符串中所有的特殊HTML字符都需要用实体引用来代替(比如<代替<)。
- cap_first:字符串的第一个字母变为大写形式;
- lower_case:字符串的小写形式;
- upper_case:字符串的大写形式;
- trim:去掉字符串首尾的空格;
序列使用的内建函数:
- size:序列中的元素的个数
数字使用的内建函数:
- int:数字的整数部分(比如-1.9?int就是-1)
示例:
${test?html}
${test?upper_case?html}
输出是:
Tom & Jerry
TOM & JERRY
3.3.12 方法调用
假设程序员定义了一个可供调用的方法repeat。第一个参数字符串类型,第二个参数是数值类型。
${repeat("What", 3)}
打印出:
WhatWhatWhat
3.3.13 处理不存在的值
要注意这个操作是FreeMarker2.3.7版本以后才有的(用来代替内建函数default,exists和if_exists);
3.3.13.1 默认值
unsafe_expr!default_expr或 unsafe_expr! 或 (unsafe_expr)!default_expr 或 (unsafe_expr)!
${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}
将会输出:
No mouse.
Jerry
默认值可以是任何类型的表达式,也可以不必是字符串。
hits!0;
colors!["red", "green", "blue"]
默认值表达式的复杂程序没有严格限制,你可以这么来写:
cargo.weight!(item.weight * itemCount+10)
如果默认值被忽略了,那么结果将会是空串,空序列或空哈希表。
(${mouse!})
<#assign mouse = "Jerry">
(${mouse!})
输出为:
()
(Jerry)
在不是顶层变量时,默认的操作符可以有两种方式:
product.color!"red"
当color不存在时(返回“red”)将会被处理,但是如果连product都不存在时将不会处理,也就是说这种写法product必须存在,否则模板就会报错。
(product.color)!"red"
这种写法,如果product不存在或者product存在而color不存在,都能显示默认值“red”而不会报错。
默认值操作也可以作用于序列,比如:
<#assign seq = ['a', 'b']>
${seq[0]!'-'}
${seq[1]!'-'}
${seq[2]!'-'}
${seq[3]!'-'}
输出为:
a
b
\-
\-
3.3.13.2 检测不存在的值
unsafe_expr??或者(unsafe_expr)??
<#if mouse??>
Mouse found
<#else>
No mouse found
</#if>
Creating mouse...
<#assign mouse = "Jerry">
<#if mouse??>
Mouse found
<#else>
No mouse found
</#if>
输出为:
No mouse found
Creating mouse...
Mouse found
3.3.14 括号
3.3.15 表达式中的空格
FTL忽略表达式中的多余空格。
3.3.16 操作符的优先级
3.4 插值