1、
、、
、快速入门
快速入门快速入门
快速入门
(
((
(1)
))
)
模板
个人简介word模板免费下载关于员工迟到处罚通告模板康奈尔office模板下载康奈尔 笔记本 模板 下载软件方案模板免费下载
模板模板
模板 + 数据模型
数据模型数据模型
数据模型 = 输出
输出输出
输出
FreeMarker基于
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
者和程序员是具有不同专业技能的不同个体的观念
他们是分工劳动的:设计者专注于
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示——创建 HTML 文件、图片、Web 页面的其它
可视化方面;程序员创建系统,生成设计页面要显示的数据
经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是
无效的,是基于动态数据的
在这里,你可以在 HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会
在输出页面给最终用户时,用适当的数据替代这些代码
下面是一个例子:
Welcome!
Welcome ${user}!
Our latest product:
${latestProduct.name}!
这个例子是在简单的 HTML 中加入了一些由${…}包围的特定代码,这些特定代码是
FreeMarker的指令,而包含 FreeMarker的指令的文件就称为模板(Template)
至于 user、latestProduct.url和 latestProduct.name来自于数据模型(data model)
数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,
甚至于在程序中直接生成
模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型
下面是一个可能的数据模型:
(root)
|
+- user = "Big Joe"
|
+- latestProduct
|
+- url = "products/greenmouse.html"
|
+- name = "green mouse"
数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而 user、url和 name
看作是文件,url和 name文件位于 latestProduct目录中(这只是一个比喻,实际并不存在)
当 FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出:
Welcome!
Welcome Big Joe!
Our latest product:
green mouse!
(
((
(2)
))
)数据模型
数据模型数据模型
数据模型
典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子:
(root)
|
+- animals
| |
| +- mouse
| | |
| | +- size = "small"
| | |
| | +- price = 50
| |
| +- elephant
| | |
| | +- size = "large"
| | |
| | +- price = 5000
| |
| +- python
| |
| +- size = "medium"
| |
| +- price = 4999
|
+- test = "It is a test"
|
+- whatnot
|
+- because = "don't know"
类似于目录的变量称为 hashes,包含保存下级变量的唯一的查询名字
类似于文件的变量称为 scalars,保存单值
scalars保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)和数字(不
要用引号将数字括起,这会作为字符串处理)
对 scalars的访问从 root开始,各部分用“.”分隔,如 animals.mouse.price
另外一种变量是 sequences,和 hashes类似,只是不使用变量名字,而使用数字索引,
如下面的例子:
(root)
|
+- animals
| |
| +- (1st)
| | |
| | +- name = "mouse"
| | |
| | +- size = "small"
| | |
| | +- price = 50
| |
| +- (2nd)
| | |
| | +- name = "elephant"
| | |
| | +- size = "large"
| | |
| | +- price = 5000
| |
| +- (3rd)
| |
| +- name = "python"
| |
| +- size = "medium"
| |
| +- price = 4999
|
+- whatnot
|
+- fruits
|
+- (1st) = "orange"
|
+- (2nd) = "banana"
这种对 scalars的访问使用索引,如 animals[0].name
(
((
(3)
))
)模板
模板模板
模板
在 FreeMarker模板中可以包括下面三种特定部分:
${…}:称为 interpolations,FreeMarker会在输出时用实际值进行替代
FTL标记(FreeMarker模板语言标记):类似于 HTML标记,为了与 HTML标记区
分,用#开始(有些以@开始,在后面叙述)
注释:包含在<#--和-->(而不是)之间
下面是一些使用指令的例子:
if指令
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#else>
Pythons are not cheaper than elephants today.
#if>
list指令
We have these animals:
Name | Price
<#list animals as being>
|
---|
${being.name} | ${being.price} Euros
#list>
|
输出为:
We have these animals:
Name | Price
|
---|
mouse | 50 Euros
|
elephant | 5000 Euros
|
python | 4999 Euros
|
include指令
Test page
Test page
Blah blah...
<#include "/copyright_footer.html">
一起使用指令
We have these animals:
Name | Price
<#list animals as being>
|
---|
<#if being.size = "large">#if>
${being.name}
<#if being.size = "large">#if>
| ${being.price} Euros
#list>
|
2222、、、、数据模型数据模型数据模型数据模型
(
((
(1
11
1)
))
)基础
基础基础
基础
在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和
sequences,其实还可以有其它更多的能力:
scalars:存储单值
hashes:充当其它对象的容器,每个都关联一个唯一的查询名字
sequences:充当其它对象的容器,按次序访问
方法:通过传递的参数进行计算,以新对象返回结果
用户自定义 FTL标记:宏和变换器
通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例
子:
(root)
|
+- mouse = "Yerri"
|
+- age = 12
|
+- color = "brown">
mouse既是 scalars又是 hashes,将上面的数据模型合并到下面的模板:
${mouse} <#-- use mouse as scalar -->
${mouse.age} <#-- use mouse as hash -->
${mouse.color} <#-- use mouse as hash -->
输出结果是:
Yerri
12
brown
(
((
(2
22
2)
))
)Scalar
ScalarScalar
Scalar 变量
变量变量
变量
Scalar 变量存储单值,可以是:
字符串:简单文本,在模板中使用引号(单引号或双引号)括起
数字:在模板中直接使用数字值
日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);
通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们
布尔值:true 或 false,通常在<#if …>标记中使用
(
((
(3
33
3)
))
)hashes
hashes hashes
hashes 、
、、
、sequences
sequencessequences
sequences 和集合
和集合和集合
和集合
有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:
hashes:具有一个唯一的查询名字和它包含的每个变量相关联
sequences:使用数字和它包含的每个变量相关联,索引值从 0开始
集合变量通常类似 sequences,除非无法访问它的大小和不能使用索引来获得它的子变
量;集合可以看作只能由<#list …>指令使用的受限 sequences
(
((
(4
44
4)
))
)方法
方法方法
方法
方法变量通常是基于给出的参数计算值
下面的例子假设程序员已经将方法变量 avg 放到数据模型中,用来计算数字平均值:
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)}
(
((
(5
55
5)
))
)宏和变换器
宏和变换器宏和变换器
宏和变换器
宏和变换器变量是用户自定义指令(自定义 FTL标记),会在后面讲述这些高级特性
(
((
(6
66
6)
))
)节点
节点节点
节点
节点变量表示为树型结构中的一个节点,通常在 XML处理中使用,会在后面的专门章节
中讲述
3
33
3、
、、
、模板
模板模板
模板
(
((
(1
11
1)
))
)整体结构
整体结构整体结构
整体结构
模板使用 FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:
文本:直接输出
Interpolation:由${和},或#{和}来限定,计算值替代输出
FTL标记:FreeMarker指令,和 HTML标记类似,名字前加#予以区分,不会输出
注释:由<#--和-->限定,不会输出
下面是以一个具体模板例子:
[BR]
[BR]
Welcome![BR]
[BR]
[BR]
<#-- Greet the user with his/her name -->[BR]
Welcome ${user}!
[BR]
We have these animals:[BR]
[BR]
<#list animals as being>[BR]
- ${being.name} for ${being.price} Euros[BR]
#list>[BR]
[BR]
[BR]
[BR]是用于换行的特殊字符序列
注意事项:
FTL区分大小写,所以 list是正确的 FTL指令,而 List不是;${name}和${NAM
E}是不同的
Interpolation只能在文本中使用
FTL标记不能位于另一个 FTL标记内部,例如:
<#if <#include 'foo'>='bar'>...
注释可以位于 FTL标记和 Interpolation内部,如下面的例子:
Welcome ${user <#-- The name of user -->}!
[BR]
We have these animals:[BR]
[BR]
<#list <#-- some comment... --> animals as <#-- again... --> being>[BR]
...
多余的空白字符会在模板输出时移除
(
((
(2
22
2)
))
)指令
指令指令
指令
在 FreeMarker中,使用 FTL标记引用指令
有三种 FTL标记,这和 HTML标记是类似的:
开始标记:<#directivename parameters>
结束标记:#directivename>
空内容指令标记:<#directivename parameters/>
有两种类型的指令:预定义指令和用户定义指令
用户定义指令要使用@替换#,如<@mydirective>...@mydirective>(会在后面讲述)
FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:
<#list animals as being>
- ${being.name} for ${being.price} Euros
<#if use = "Big Joe">
(except for you)
#list>
#if><#-- WRONG! -->
如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息
FreeMarker会忽略 FTL标记中的空白字符,如下面的例子:
<#list[BR]
animals as[BR]
being[BR]
>[BR]
${being.name} for ${being.price} Euros[BR]
#list >
但是,<、和指令之间不允许有空白字符
(
((
(3
33
3)
))
)表达式
表达式表达式
表达式
直接指定值
字符串
使用单引号或双引号限定
如果包含特殊字符需要转义,如下面的例子:
${"It's \"quoted\" and
this is a backslash: \\"}
${'It\'s "quoted" and
this is a backslash: \\'}
输出结果是:
It's "quoted" and
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 (u000
转义序列
转义序列转义序列
转义序列 含义
含义含义
含义
8)
\f
Form feed (u000
C)
\l <
\g >
\a &
\{ {
\xCode
4位 16进制 Unic
ode 代码
有一类特殊的字符串称为 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"] as x>
${x}
#list>
输出的结果是:
winter
spring
summer
autumn
列表的项目是表达式,所以可以有下面的例子:
[2 + 2, [1, 2, 3, 4], "whatnot"]
可以使用数字范围定义数字序列,例如 2..5等同于[2, 3, 4, 5],但是更
有效率,注意数字范围没有方括号
可以定义反递增的数字范围,如 5..2
散列(hash)
由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是
一个例子:
{"name":"green mouse", "price":150}
键和值都是表达式,但是键必须是字符串
获取变量
顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,
且不能以数字开头
从散列中获取数据
可以使用点语法或方括号语法,假设有下面的数据模型:
(root)
|
+- book
| |
| +- title = "Breeding green mouses"
| |
| +- author
| |
| +- name = "Julia Smith"
| |
| +- info = "Biologist, 1923-1985, Canada"
|
+- test = "title"
下面都是等价的:
book.author.name
book["author"].name
book.author.["name"]
book["author"]["name"]
使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为
名字是任意表达式的结果
从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须
是数字;注意:第一个项目的索引是 0
00
0
序列片断:使用[startIndex..endIndex]
[startIndex..endIndex][startIndex..endIndex]
[startIndex..endIndex]语法,从序列中获得序列片断(也是序
列);startIndex和 endIndex是结果为数字的表达式
特殊变量:FreeMarker内定义变量,使用.variablename
.variablename.variablename
.variablename语法访问
字符串操作
Interpolation(或连接操作)
可以使用${..}
${..}${..}
${..}(或#{..}
#{..}#{..}
#{..})在文本部分插入表达式的值,例如:
${"Hello ${user}!"}
${"${user}${user}${user}${user}"}
可以使用+
++
+操作符获得同样的结果
${"Hello " + user + "!"}
${user + user + user + user}
${..}
${..}${..}
${..}只能用于文本部分,下面的代码是错误的:
<#if ${isBig}>Wow!#if>
<#if "${isBig}">Wow!#if>
应该写成:
<#if isBig>Wow!#if>
子串
例子(假设 user的值为“Big Joe”):
${user[0]}${user[4]}
${user[1..4]}
结果是(注意第一个字符的索引是 0):
BJ
ig J
序列操作
连接操作:和字符串一样,使用+
++
+,下面是一个例子:
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
#list>
输出结果是:
- Joe
- Fred
- Julia
- Kate
散列操作
连接操作:和字符串一样,使用+
++
+,如果具有相同的 key,右边的值替代左边的值,
例如:
<#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 * 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
比较操作符
使用=(或==,完全相等)测试两个值是否相等,使用!=测试两个值是否不相等
=和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = "1">会引起错
误
Freemarker是精确比较,所以对"x"、"x "和"X"是不相等的
对数字和日期可以使用<、<=、>和>=,但不能用于字符串
由于 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>
内建
函
关于工期滞后的函关于工程严重滞后的函关于工程进度滞后的回复函关于征求同志党风廉政意见的函关于征求廉洁自律情况的复函
数
内建函数的用法类似访问散列的子变量,只是使用“?
??
?”替代“.
..
.”,下面列出常
用的一些函数
字符串使用的:
html:对字符串进行 HTML编码
cap_first:使字符串第一个字母大写
lower_case:将字符串转换成小写
upper_case:将字符串转换成大写
trim:去掉字符串前后的空白字符
序列使用的:
size:获得序列中元素的数目
数字使用的:
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
44
4)
))
)Interpolation
InterpolationInterpolation
Interpolation
Interpolation有两种类型:
通用 Interpolation:${expr}
数字 Interpolation:#{expr}或#{expr; format}
注意:Interpolation只能用于文本部分
通用 Interpolation
插入字符串值:直接输出表达式结果
插入数字值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输
出;可以使用内建函数 string格式化单个 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%
插入日期值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输
出;可以使用内建函数 string格式化单个 Interpolation,下面是一个使用格式模
式的例子:
${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)
插入布尔值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输
出;可以使用内建函数 string格式化单个 Interpolation,下面是一个例子:
<#assign foo=true/>
${foo?string("yes", "no")}
输出结果是:
yes
数字 Interpolation的#{expr; format}形式可以用来格式化数字,format可以是:
mX:小数部分最小 X位
MX:小数部分最大 X位
例子:
<#-- 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 -->
4444、、、、杂项杂项杂项杂项
(
((
(1
11
1)
))
)用户定义指令
用户定义指令用户定义指令
用户定义指令
宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使
用 macro指令定义,而变换器是在模板外由程序定义,这里只介绍
宏
基本用法
� 宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,
下面是一个例子:
<#macro greet>
Hello Joe!
#macro>
� 作为用户定义指令使用宏变量时,使用@替代 FTL标记中的#
<@greet>@greet>
� 如果没有体内容,也可以使用:
<@greet/>
参数
� 在 macro指令中可以在宏变量之后定义参数,如:
<#macro greet person>
Hello ${person}!
#macro>
� 可以这样使用这个宏变量:
<@greet person="Fred"/> and <@greet person="Batman"/>
输出结果是:
Hello Fred!
and Hello Batman!
� 宏的参数是 FTL表达式,所以下面的代码具有不同的意思:
<@greet person=Fred/>
� 这意味着将 Fred变量的值传给 person参数,该值不仅是字符串,还可以是其它
类型,甚至是复杂的表达式
� 宏可以有多参数,下面是一个例子:
<#macro greet person color>
Hello ${person}!
#macro>
� 可以这样使用该宏变量:
<@greet person="Fred" color="black"/>
� 其中参数的次序是无关的,因此下面是等价的:
<@greet color="black" person="Fred"/>
� 只能使用在 macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是
错误的:
<@greet person="Fred" color="black" background="green"/>
<@greet person="Fred"/>
� 可以在定义参数时指定缺省值,如:
<#macro greet person color="black">
Hello ${person}!
#macro>
� 这样<@greet person="Fred"/>就正确了
� 宏的参数是局部变量,只能在宏定义中有效
嵌套内容
� 用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间
的模板片断
� 例子:
<#macro border>
#macro>
这样使用该宏变量:
<@border>The bordered text@border>
输出结果:
� <#nested>指令可以被多次调用,例如:
<#macro do_thrice>
<#nested>
<#nested>
<#nested>
#macro>
<@do_thrice>
Anything.
@do_thrice>
输出结果:
Anything.
Anything.
Anything.
� 嵌套内容可以是有效的 FTL,下面是一个有些复杂的例子:
<@border>
<@do_thrice>
- <@greet person="Joe"/>
@do_thrice>
@border>
输出结果:
- Hello Joe!
- Hello Joe!
- Hello Joe!
|
� 宏定义中的局部变量对嵌套内容是不可见的,例如:
<#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: ? ? ?
�
在宏定义中使用循环变量
� 用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为 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!
� 指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题
� 调用时少指定循环变量,则多指定的值不可见
� 调用时多指定循环变量,多余的循环变量不会被创建
((((2222))))在模板中定义变量在模板中定义变量在模板中定义变量在模板中定义变量
在模板中定义的变量有三种类型:
� plain 变量:可以在模板的任何地方访问,包括使用 include 指令插入
的模板,使用 assign 指令创建和替换
� 局部变量:在宏定义体中有效,使用 local 指令创建和替换
� 循环变量:只能存在于指令的嵌套内容,由指令(如 list)自动创建;
宏的参数是局部变量,而不是循环变量
局部变量隐藏(而不是覆盖)同名的 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>
输出结果: