Freemarker是什么
- FreeMarker是模版引擎:是一种基于模版和要改变的数据,并用来生成(HTML页面、邮件、配置文件、源代码等)的通用工具。
用Freemarker的理由
1、性能。velocity应该是最好的,其次是jsp,普通的页面freemarker性能最差(虽然只是几毫秒到十几毫秒的差距)。但是在复杂页面上(包含大量判断、日期金额格式化)的页面上,freemarker的性能比使用tag和el的jsp好。
2、宏定义比jsp tag方便
3、内置大量常用功能。比如html过滤,日期金额格式化等等,使用非常方便
4、支持jsp标签
5、可以实现严格的mvc分离
Freemarker规则整理
FreeMarker模版文件主要有4部分组成:
- 文本:直接输出的部分;
- 插值:
${}
#{}
格式的部分,将使用数据模型中的部分替代输出; - FTL指令:FreeMarker指定的和HTML标记类似的标签,名字前加
#
用来区分,不输出; - 注释:
<#--此处为注释文本-->
,不输出;
<html>
<head>
<title>welcome to FreeMarker</title>
</head>
<body>
<#--此处为注释-->
<#-- 下面为插值 -->
<h2>Welcome ${user} !</h2>
<#-- 下面为FTL指令 -->
<#list>
<li>${sth.name} for ${sth.price}</li>
</list>
</body>
</html>
插值规则
FreeMarker的差值有两种类型:
- 通用插值
${expr}
- 数字格式化插值
#{expr}
或#{expr;format}
基本输出:
- 输出
${user.name}
- 空值判断
${user.name?if_exists}
${user.name?default('xxx')}
${user.name!"xxx"} 默认值xxx
- 日期格式
${user.name?string('yyyy-MM-dd')}
- 数字格式
${age?string.number} //20
${age?string.currency} //$20.00
${age?string.percent} //20%
FTL指令规则
在FreeMarker中,使用FTL标签来使用指令,FreeMarker有3种FTL标签,与HTML类似:
- 开始标签
<#directName param>
- 结束标签
</#directName>
- 空标签
<#directName param />
遍历List集合
<#-- 逐个输出list中的元素:a b c d -->
<#list ['a','b','c','d'] as item>
${itam}
</#list>
迭代集合对象时,还包含两个特殊的循环便量:item_index
当前变量的索引值;item_has_next
是否存在下一个对象;也可以使用<#break>
指令跳出迭代。
遍历map集合
{"liu":100, "sun":120}
<#list map ? keys as key>
${key}=${map[key]}
</#list>
逻辑判断
- if判断
<#if condition1>
<#elseif condition2>
...
<#else>
</#if>
- switch判断
<#switch value>
<#case refValue>
<#break>
<#case refValue2>
<#break>
<#default>
</#switch>
内置函数
常用的内置的字符串函数:
html
对字符串进行HTML编码cap_first
使字符串第一个字母大写lower_case
将字符串转换为小写upper_case
将字符串转换为大写trim
去掉字符串前后的空白字符
常用的内置的集合的函数
size
获取序列中元素的个数chunk
分成几个一组xxx_index
计数器
常用的内置的数字值的函数
int
获得数字的整数部分,带符号
空值处理
- FreeMarker对空值的处理非常严格,FreeMarker的变量必须有值,没有被赋值的变量就会抛出异常,因为FreeMarker未赋值的变量强制出错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误.这里所说的空值,实际上也包括那些并不存在的变量,对于一个Java的null值而言,我们认为这个变量是存在的,只是它的值为null,但对于FreeMarker模板而言,它无法理解null值,null值和不存在的变量完全相同
- 为了处理缺失变量,FreeMarker提供了两个运算符:
!
指定缺失变量的默认值??
判断某个变量是否存在- 其中
!
运算符的用法有两种:variable!
variable!defaultValue
,第一种用法不给缺失的变量指定默认值,表明默认值是空字符串,长度为0的集合,或者长度为0的Map对象; - 使用
!
指定默认值时,并不要求默认值的类型和变量类型相同。使用??
运算符总是返回一个布尔值,用法为variable??
如果该变量存在则返回true,否则返回false。
变量的声明
plain变量
:可以在模版的任何地方访问,包括使用include
指令插入的模版,使用assign
指令创建和替换
<#assign num=0 />
<#assign x="Hello ${user}!">
- 局部变量:在宏定义体中有效,使用
local
指令创建和替换;注意:宏的参数是局部变量,不是循环变量; - 循环变量:只能存在于指令的嵌套内容,由指令(如
list指令
)自动创建;
运算符的优先级
FreeMarker中运算符的优先级如下(高–>低)
- 一元运算符
!
- 内建函数
?
- 乘除法
*
/
%
- 加减法
+
-
- 比较
>
<
>=
<=
lt
lte
gt
gte
- 相等
==
=
!=
- 逻辑与
&&
- 逻辑或
||
- 数字范围
...
其他指令
include指令
include指令
:包含作用;用于包含指定页。<#include filename [options]>
- filename:该参数指定被包含的模版文件
- options:该参数可以省略,指定包含时的选项,包含
encoding
和parse
两个选项,其中encoding
指定了包含页面时所用的解码集,parse
指定被包含文件是否作为FTL文件来解析,默认true。
import指令
import指令
:该指令用于导入FreeMarker模版中的所有变量,并将该变量放置在指定的Map对象中。<#import "/lib/common.ftl" as com>
- 上述代码将导入 /lib/common.ftl 模版文件中的所有变量,将这些变量放在一个名为
com
的map对象中
setting指令
setting指令
:该指令用于设置FreeMarker的运行环境<#setting name=value>
- 其中
name
取值范围如下:
locale
:指定该模版所用国家/语言选项number_format
:指定格式化输出数字的格式boolean_format
:指定两个布尔值的语法格式,默认为true
false
date_format
time_format
datetime_format
:指定格式化输出日期的格式time_zone
:设置格式化输出日期时所使用的时区
macro
nested
return
指令
macro指令
:用于实现自定义指令,通过使用自定义指令,可以将一段模版片段定义为一个用户指令
<#macro name param1 param2 param3>
...
<#nested loopvar1, loopvar2, loopvar3>
...
<#return>
</#macro>
- 上述指令中:
- name 属性指定该自定义指令的名字,使用自定义指令时可以传入多个参数
- param 该指令是使用自定义指令时的参数,使用时必须为参数传入值
nested指令
:输出使用自定义指令时的中间部分return指令
:可用于随时结束该自定义指令
宏
宏是什么
- 宏是在模版中使用
macro指令
定义 - 宏是和某个变量关联的模版片段,以便在模版中通过用户定义指令使用该变量
为什么使用宏
宏的用法
注意点:调用宏时,与使用FreeMarker的其他指令类似,只是使用@
替代FTL标记中的#
macro
定义模版,然后调用直接显示
<#macro greet>
<font size="+3">Hello macro!</font>
</#macro>
<@greet></@greet>
结果:<font size="+3">Hello macro!</font>
在macro
指令中可以在宏变量之后定义参数
<#macro greet person>
<font size="+3">Hello ${person}!</font>
</#macro>
<@greet person="Fred" />
结果:<font size="+3">Hello Fred!</font>
macro
定义多个参数
<#macro greet person color="black">
<font size="+3" color="${color}">Hello ${person}!</font>
</#macro>
自定义指令嵌套内容<#nested>
<#macro border>
<table border=4 cellspacign=0 cellpadding=4>
<tr><td><#nested></td></tr>
</table>
</#macro>
<@border>The border text</@border>
结果:
<table border=4 cellspacign=0 cellpadding=4>
<tr><td>The border text</td></tr>
</table>
记住:<#nested>
就相当于占位符
<#nested>
指令可以被多次调用
<#macro do_thrice>
<#nested>
<#nested>
<#nested>
</#macro>
<@do_thrice>Some text
结果:Some text Some text Some text
局部变量对嵌套内容不可见
<#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_name param_list; loop_variable_list>
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4; c, half, last>
${c}.${halfc}<#if last>Last!</#if>
</@repeat>
其中,count
是宏的参数,c, half, last
是循环变量
结果:
1,0.5
2 1
3 1.5
4 2 Last!
循环变量和宏标记指定的不同不会有问题,若调用时少指定了循环变量,那么多余的值不可见;若调用时多指定了循环变量,多余的循环变量不会被创建。