Freemarker 语法简介
来源:互联网 发布:淘宝返利是怎么回事 编辑:程序博客网 时间:2024/05/17 21:05
FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML 网页、电子邮件、配置文件、源代码等)的通用工具。
选择 freemarker 的原因:
- 性能。velocity 应该是最好的,其次是 jsp,普通的页面 freemarker 性能最差(虽然只是几毫秒到十几毫秒的差距)。但是在复杂页面上(包含大量判断、日期金额格式化)的页面上,freemarker 的性能比使用 tag 和 el 的 jsp 好。
- 宏定义比 jsp tag 方便
- 内置大量常用功能。比如 html 过滤,日期金额格式化等等,使用非常方便
- 支持 jsp 标签
- 可以实现严格的 mvc 分离
FreeMarker 模板文件主要由如下 4 个部分组成:
- 文本:直接输出的部分。
- 注释:
<#-- ... —>
格式部分,不会输出。 - 插值:即
${…}
或#{…}
格式的部分,将使用数据模型中的部分替代输出。 - FTL 指令:FreeMarker 指定,和 HTML 标记类似,名字前加
#
予以区分,不会输出。
例子
<html> <head> <title>Welcome!</title> </head> <body> <#-- 注释部分 --> <#-- 下面使用插值 --> <h1>Welcome ${user}!</h1> <p>We have these animals: <ul> <#-- 使用FTL指令 --> <#list animals as being> <li>${being.name} for ${being.price} Euros </#list> </ul> </body></html>
一、插值规则
FreeMarker 的插值有如下两种类型:
- 通用插值
${expr}
- 数字格式化插值:
#{expr}
或#{expr;format}
1. 通用插值
- 输出
${book.name}
- 空值判断:
${book.name?if_exists}
${book.name?default(‘xxx’)} //默认值xxx
${book.name!"xxx"} //默认值xxx
- 日期格式:
${book.date?string('yyyy-MM-dd')}
- 数字格式:
${book?string.number} //20
${book?string.currency} //$20.00
${book?string.percent} //20%
. 数字格式化插值
数字格式化插值可采用#{expr;format}
形式来格式化数字。
其中format
可以是:
mX
: 小数部分最小 X 位MX
: 小数部分最大 X 位
示例:
<#assign x=2.582/><#assign y=4/>#{x; M2}#{y; M2}#{x; m2}#{y; m2}#{x; m1M2}#{x; m1M2}
输出:
2.5842.584.002.582.58
二、FTL 指令规则
在 FreeMarker 中, 使用 FTL 标签来使用指令, FreeMarker 有 3 种 FTL 标签, 这和 HTML 标签是完全类似的.
- 开始标签:
<#directivename parameter>
- 结束标签:
</#directivename>
- 空标签:
<#directivename parameter/>
1. 遍历 List 集合
<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as item>${item}</#list>
这里会逐个输出星期几。
此外,迭代集合对象时,还包含两个特殊的循环变量:
item_index
: 当前变量的索引值item_has_next
: 是否存在下一个对象
也可以使用<#break>
指令跳出迭代。
2. 遍历 map 集合
{"语文":78, "数学":80}Map 对象的 key 和 value 都是表达式,但是 key 必须是字符串。
<#list map?keys as key> ${key}=${map[key]}<br/></#list>
3. 逻辑判断
if 判断
判断条件,当 condition 的判断结果为false
(布尔值)时,在<#if condition>
和</#if>
标签之间的内容将会被略过。
<#if animals.python.price < animals.elephant.price>Pythons are cheaper than elephants today.<#else>Pythons are not cheaper than elephants today.</#if>
需要注意的是比较运算符两边的类型必须相同,不能一个是 数字,一个是字符串,否则将会报错。
Switch 判断
<#switch value> <#case refValue1> ... <#break> <#case refValue2> ... <#break> <#case refValueN> ... <#break> <#default> ...</#switch>
4. 空值处理
FreeMarker 对空值的处理非常严格,FreeMarker 的变量必须有值,没有被赋值的变量就会抛出异常,因为 FreeMarker 未赋值的变量强制出错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误。这里所说的空值,实际上也包括那些并不存在的变量,对于一个 Java 的null
值而言,我们认为这个变量是存在的,只是它的值为null
,但对于 FreeMarker 模板而言,它无法理解null
值,null
值和不存在的变量完全相同。
为了处理缺失变量, FreeMarker 提供了两个运算符:
!
: 指定缺失变量的默认值??
: 判断某个变量是否存在
指定缺失变量的默认值
!
运算符的用法有如下两种:
variable!variable!defaultValue
第一种用法不给缺失的变量指定默认值,表明默认值是空字符串、长度为 0 的集合或者长度为 0 的 Map 对象。
另外,使用!
指定默认值时,并不要求默认值的类型和变量类型相同。
Demo:
<h1>Welcome ${user!"Anonymous"}!</h1><#assign user = "Doe Joe"><h1>Welcome ${user!"Anonymous"}!</h1>输出:
<h1>Welcome Anonymous!</h1><h1>Welcome Doe Joe!</h1>
判断某个变量是否存在
使用??
运算符非常简单,它总是返回一个布尔值,用法为:variable??
,如果该变量存在,返回true
,否则返回false
但是需要注意的是,我们在使用 freemarker 获取后端回填数据时,必须使用??
来判断是否存在,再进行使用。或者通过 default 来赋予默认值,否则一旦数据不存在,就会出现前端报错完全崩溃的情况。
Demo:
<#if mouse??>Mouse found.<#else>No mouse found.</#if>实际使用示例:
<#if !productList??><div class="n-result"> <h3>暂无内容!</h3></div><#else><div class="n-plist"> <ul class="f-cb" id="plist"> <#list productList as x> <#if !x.isBuy> <li id="p-${x.id}"> <a href="/show?id=${x.id}" class="link"> <div class="img"><img src="${x.image}" alt="${x.title}"></div> <h3>${x.title}</h3> <div class="price"><span class="v-unit">¥</span><span class="v-value">${x.price}</span></div> </a> </li> </#if> </#list> </ul></div></#if>
5. 变量的声明
plain 变量
它能从模板中的任何位置来访问,或者从使用 include 指令引入的模板访问。可以使用assign
和macro
指令来创建或替换这些变量。
<#assign num=0/><#assign x="Hello ${user}!"/>
局部变量
只能在#function
或#macro
定义体中定义 & 有效,使用 local 指令创建和替换。
局部变量会隐藏同名的 plain 变量。
循环变量
只能存在于指令的嵌套内容,由指令(如 list)自动创建;宏的参数是局部变量,而不是循环变量。
循环变量会隐藏同名的局部变量和 plain 变量,且内部循环变量会隐藏外部循环变量。
如果想要跳出作用域,直接使用数据模型中的变量,使用 globals 关键字即可:
<#assign user = "Joe">${user}${.globals.user}输出:
JoeDoe
6. 运算符的优先级
FreeMarker 中的运算符优先级如下 (由高到低排列):
- 一元运算符:
!
- 内建函数:
?
- 乘除法:
*
,/
,%
- 加减法:
-
,+
- 比较:
>
,<
,>=
,<=
- 相等:
==
,=
,!=
- 逻辑与:
&&
- 逻辑或:
||
- 数字范围:
..
7. include 指令
include 指令的作用类似于 JSP 的包含指令,用于包含指定页。include 指令的语法格式如下:<#include filename [options]>示例:
<#include "/header.html"><#include "/footer.ftl">
8. import 指令及命名空间
import
指令类似于 java 里的 import,它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件。
我们通过 assign 和 macro 创建的变量的集合就是命名空间。命名空间的作用在各种编程语言中都已见识,这里假设我们定义了自己的 macro 和 assign 位于 lib/mylib.ftl 中。
<#macro copyright date><p>Copyright (C) ${date} Julia Smith. All rights reserved.</p></#macro><#assign mail = "jsmith@acme.com">通过 import 来引用:
<#import "/libs/mylib.ftl" as my> <#-- 被称为"my"的哈希表就会是那个"大门" --> <@my.copyright date="1999-2002"/>${my.mail}输出:
<p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>jsmith@acme.com
覆盖变量
引入命名空间后替换变量需要在 assign 的基础上加上 in 关键字:
<#import "/lib/mylib.ftl" as my>${my.mail}<#assign mail = "jsmith@other.com" in my>${my.mail}输出:
jsmith@acme.comjsmith@other.com
9. noparse 指令
noparse
指令指定 FreeMarker 不处理该指定里包含的内容,该指令的语法格<#noparse>...</#noparse>示例:
<#noparse><#list animals as animal> <li>${animal.name} for ${animal.price} Euros</li></#list></#noparse>输出:
<#list animals as animal> <li>${animal.name} for ${animal.price} Euros</li></#list>
10. setting 指令
该指令用于设置 FreeMarker 的运行环境, 该指令的语法格式如下:<#setting name=value>
在这个格式中,name
的取值范围包含如下几个:
locale
: 该选项指定该模板所用的国家 / 语言选项number_format
: 指定格式化输出数字的格式boolean_format
: 指定两个布尔值的语法格式, 默认值是 true,falsedate_format
,time_format
,datetime_format
: 指定格式化输出日期的格式time_zone
: 设置格式化输出日期时所使用的时区
三、内建函数
内建函数以?
形式提供变量的不同形式或者其他信息。多个内建函数可以通过?
连接来使用。
字符串常用的内建函数:
html
: 将字符串中的所有特殊 HTML 字符进行转义。例如:<
替换成<
cap_first
: 将字符串的首字母大写lower_case
: 将字符串转换为小写形式upper_case
: 将字符串转换为大写形式trim
: 去掉字符串首尾的空格
集合常用的内建函数:
size
: 集合中元素的个数chunk(size)
: 分成几个一组
数字常用的内建函数:
- int: 将数字转换为整数。方式为直接去除小数部分。
示例:
${test?html}${test?lower_case?html}
${3 * 2 + 2} <#-- 8 -->${3 * (2 + 2)} <#-- 12 -->${3 * ((2 + 2) * (1 / 2))} <#-- 6 -->${"green " + "mouse"?upper_case} <#-- green MOUSE -->${("green " + "mouse")?upper_case} <#-- GREEN MOUSE -->
number_to_datetime
一个转换时间格式的内建函数。
${timestamp?number_to_datetime?string["MM-dd HH:mm"]}
eval
将字符串作为 ftl 模板输出,就和 javascript 原生的 eval 有点类似。
示例:
${(col['name']?eval)}
四、宏
宏是在模板中使用 macro 指令定义,宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,有人说用 freemarker,但没有用到它的宏(macro),就等于没有真正用过 freemarker。说的就是宏是 freemarker 的一大特色。
其基本语法如下:
<#macro name param1 param2 ... paramN> ... <#nested loopvar1, loopvar2, ..., loopvarN> ... <#return> ...</#macro>
在上面的格式片段中, 包含了如下几个部分:
name
:name
属性指定的是该自定义指令的名字, 使用自定义指令时可以传入多个参数paramX
: 该属性就是指定使用自定义指令时报参数, 使用该自定义指令时, 必须为这些参数传入值nested
指令:nested
标签输出使用自定义指令时的中间部分nested
指令中的循环变量: 这此循环变量将由macro
定义部分指定, 传给使用标签的模板return
指令: 该指令可用于随时结束该自定义指令.
需要注意的是:调用宏时,与使用 FreeMarker 的其他指令类似,只是使用@
替代 FTL 标记中的#
。
1. macro 定义模板,然后调用直接显示
<#macro greet><font size="+2">Hello World!</font></#macro>
使用:
<@greet/><@greet></@greet>输出:
<font size="+2">Hello World!</font><font size="+2">Hello World!</font>
2. 在 macro 指令中可以在宏变量之后定义参数
<#macro greet person><font size="+2">Hello ${person}!</font></#macro>
使用:
<@greet person="Doe"></@greet><@greet person="Joe"/><@greet "Foo"/>
输出:
<font size="+2">Hello Doe!</font><font size="+2">Hello Joe!</font><font size="+2">Hello Foo!</font>
3. macro 定义多个参数
macro 可以有多个参数,参数的次序是无关的(如果使用 Postional style 调用则需要按顺序),在 macro 指令中只能使用定义的参数,并且必须对所有参数赋值,可以在定义参数时指定缺省值:<#macro greet person color="black"><font size="+2" color="${color}">Hello ${person}!</font></#macro>
使用:
<#-- Named style --><@greet person="Doe"></@greet><@greet person="Doe"/><@greet person="Doe" color= "green"/><#-- Postional style --><@greet "Doe"/><@greet "Doe", "green"/>
输出:
<font size="+2" color="black">Hello Doe!</font><font size="+2" color="black">Hello Doe!</font><font size="+2" color="green">Hello Doe!</font><font size="+2" color="black">Hello Doe!</font><font size="+2" color="green">Hello Doe!</font>
4. 自定义指令嵌套内容 <#nested>
<#macro border><table border=4 cellspacing=0 cellpadding=4> <tr> <td> <#nested> </td> </tr></table></#macro>
使用:
<@border>The bordered text</@border>
输出:
<table border=4 cellspacing=0 cellpadding=4> <tr> <td> The bordered text </td> </tr></table>
<#nested>
就相当于占位符
<#nested>
指令可以被多次调用:
<#macro do_thrice> <#nested> <#nested> <#nested></#macro>
使用:
<@do_thrice>Anything.</@do_thrice>
输出:
Anything.Anything.Anything.
5. 局部变量对嵌套内容不可见
<#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: ? ? ?
其中嵌套内容中的y
,x
,count
都是没定义的,所以取不到值。
6. 宏定义中使用循环变量
nested 指令也可以有循环变量(循环变量的含义见下节),调用宏的时候在宏指令的参数后面,分号隔开依次列出循环变量的名字,格式如下:<@macro_name paramter list; loop variable list[,]>
示例:
<#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>
count
是宏的参数,c
,halfc
,last
则为循环变量,与宏中<#nested>
里定义的x
,x/2
,x==count
一一对应。输出:
1, 0.52, 13, 1.54, 2 Last!
引用
循环变量和宏标记指定的不同不会有问题,如果调用时少指定了循环变量,那么多余的值不可见。调用时多指定了循环变量,多余的循环变量不会被创建:<@repeat count=4 ; c, halfc, last>${c}. ${halfc}<#if last> Last!</#if></@repeat><@repeat count=4 ; c, halfc>${c}. ${halfc}</@repeat><@repeat count=4>Just repeat it...</@repeat>
转载自:https://hran.me/archives/freemarker.html
- Freemarker语法简介
- Freemarker语法简介
- Freemarker 语法简介
- freemarker语法
- freemarker语法
- freemarker语法
- freemarker语法
- freemarker语法
- FreeMarker 语法
- Freemarker语法
- freemarker语法
- freemarker语法
- freemarker语法
- freeMarker语法
- freemarker语法
- freemarker语法
- freemarker语法
- FreeMarker 简介
- React 初探
- 计蒜客-2017 计蒜之道 初赛 第六场-A-微软手机的信号显示
- jquery跨域 jsonp
- Django Tutorial Part4
- JPEG to PDF V3.7 汉化版,tek2y原创汉化!
- Freemarker 语法简介
- remove-duplicates-from-sorted-array
- 闭包的作用
- 2017四川省赛A题Simple Arithmetic
- Hibernate入门08_HQL查询
- 《Boost程序完全开发》跟踪学习训练一:Boost::date_time库的使用
- 死磕《Effective Java中文版》-八挂作者
- Python 中文分词 NLPIR 快速搭建
- 【排序】 快速排序代码-C语言版