freemarker入门part1
FreeMarker是一个模板引擎,一个将数据应用至固定模板的java工具包。模板使用ftl(FreeMarker Template Language)编写,数据通常
由常见的编程语言(如Java)来处理和生成。FreeMarker通常见于MVC(Model View Controller)模式,常用来处理动态web页面。通过
FreeMarker设计者可以不考虑负责的业务逻辑直接修改ftl,而开发者不用关心设计元素的问题,专注于业务逻辑处理。
特性
1. 强大的模板语言:支持条件、循环、字符和数字操作及格式化等
2. 多用途和轻量级:0依赖,支持任何输出格式
3. 国际化:支持国际化数字、时区、模板变量等
4. XML处理能力
5. 丰富的数据模型
快速开始
指令
if/else/elseif(条件)
<#if animals.python.price != 0>
Pythons are not free today!
</#if>
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#else>
Pythons are not cheaper than elephants today.
</#if>
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#elseif animals.elephant.price < animals.python.price>
Elephants are cheaper than pythons today.
<#else>
Elephants and pythons cost the same today.
</#if>
list(循环)
<#list sequence as loopVariable>repeatThis</#list>
<p>We have these animals:
<table border=1>
<#list animals as animal>
<tr><td>${animal.name}<td>${animal.price} Euros
</#list>
</table>
<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, </#list>
最后一个元素忽略<#sep>后面内容
<p>Fruits: <#list misc.fruits as fruit>${fruit}<#sep>, <#else>None</#list>
include
用于将其他文件内容引入到模板
公共内容
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
引用公共内容
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>
内置函数
user?upper_case: 大写处理
animal.name?cap_first: 大写首字母
user?length: 变量长度(如字符串)
animals?size: 变量大小(如数组)
animal?index: 循环数组时元素的索引(从0开始)
animal?count: 循环数组时元素的计数(从1开始)
animal?item_parity: 返回odd或even(通常用于样式处理)
animal.protected?string("Y", "N"): 字符串处理
animal?item_cycle('lightRow', 'darkRow'): 样式处理
fruits?join(", "): 列表转字符串,元素间用,号分隔
user?starts_with("J"): 变量是否已J开头,返回布尔值
更多内置函数见https://freemarker.apache.org/docs/ref_builtins.html
处理不存在变量
如果变量可能为选填,需要做特殊处理。这里不存在包含变量真的不存在和变量值为null。
设置默认值用!
<h1>Welcome ${user!"visitor"}!</h1>
是否存在用??
<#if user??><h1>Welcome ${user}!</h1></#if>
多级变量用()??
(animals.python.price)??
转义HTML/XML等标记语言
FreeMarker可以配置自动转义${}里面的内容
设置ftl格式,可以转义变量内容
<#ftl output_format="HTML">
各种格式转义规则见https://freemarker.apache.org/docs/dgui_misc_autoescaping.html
数据类型
普通类型
String: 字符串(用单或双引号都可)
Number: 数字
Boolean: true/false
Date: 日期时间
Date: 日期
Time: 时间
Data-time: 日期时间
容器类型
FreeMarker不支持在ftl对容器的增删改,但是可以将两个存在的容器加一起(用+)
Hash: k/v(字典或Map)
Sequence: 序列(从0开始)
Collection: 集合
子程序
方法or函数
类似函数式编程处理(比如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 a python and an elephant is: ${avg(animals.python.price, animals.elephant.price)}
用户自定义指令
后续详细说明
<@box title="Attention!">
Too much copy-pasting may leads to
maintenance headaches.
</@box>
模板
总览
模板就是你写的一堆ftl文件(区分大小写)
ftl包含以下内容
Text: 文本
Interpolation: 占位符(${} )
FTL Tag: 类似HTML的Tags(<#if>)
注释: <#-- -->
指令
指令由开始标签和结束标签组成,类似HTML的标签。指令分为两种:预定义指定和用户自定义指令
指令可以配置为[#if],也可以配置为
详见https://freemarker.apache.org/docs/ref_depr_oldsyntax.html 和 https://freemarker.apache.org/docs/dgui_misc_alternativesyntax.html
表达式
直接赋值
字符串
如带引号空格的字符串,用到转义符
${"It's \"quoted\" and
this is a backslash: \\"}
${'It\'s "quoted" and
this is a backslash: \\'}
${r"${foo}"}
${r"C:\foo\bar"}
数字
不支持科学计数(1E3)和不完整数字(.5)
0.08, -5.013, 8, 008, 11, +11
布尔
true or false
序列
支持不同类型放同一序列,支持表达式
<#list ["foo", "bar", "baz"] as x>
${x}
</#list>
[2 + 2, [1, 2, 3, 4], "foo"]
范围
类似序列,元素为数字
start..end: 1..4 或 4..1
start..<end: 1..<4
start..*length: 10..*4 等价于 [10, 11, 12, 13];10..*-4 等价于 [10, 9, 8, 7]
start..: 1.. 等价于 [1, 2, 3, 4, 5, 6, ... ]
散列表
{ "name": "green mouse", "price": 150 }
获取变量
顶部变量
${user}
散列表获取
book.title
book.author.name
book["author"].name
序列获取
animals[0].name
字符串操作
赋值和拼接
<#assign s = "Hello ${user}!">
${s} <#-- Just to see what the value of s is -->
<#assign s = "Hello " + user + "!">
获取单个字符
${user[0]}
${user[4]}
获取子字符串
<#assign s = "ABCDEF">
${s[2..3]}
${s[2..<4]}
${s[2..*3]}
${s[2..*100]}
${s[2..]}
序列操作
拼接
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
</#list>
分片
<#assign seq = ["A", "B", "C", "D", "E"]>
<#list seq[1..3] as i>${i}</#list>
散列表操作
拼接
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
数字操作
${100 - x * x}
${x / 2}
${12 % 10}
${3 + "5"} 等于 35(弱语言都这么干)
-- 转int
${(x/2)?int}
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}
比较操作
<#if user == "Big Joe">
It is Big Joe
</#if>
<#if user != "Big Joe">
It is not Big Joe
</#if>
<#if x <= 12>
x is less or equivalent with 12
</#if>
逻辑操作
或|| 与&& 非!
<#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>
内置函数操作
${testSeqence[1]?cap_first}
${"horse"?cap_first}
${(testString + " & Duck")?html}
方法调用
${repeat("Foo", 3)}
${repeat(repeat("x", 2), 3) + repeat("Foo", 4)?upper_case}
默认值处理
unsafe_expr!default_expr or unsafe_expr! or (unsafe_expr)!default_expr or (unsafe_expr)!
${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}
(${mouse!})
<#assign mouse = "Jerry">
(${mouse!})
<#assign seq = ['a', 'b']>
${seq[0]!'-'}
${seq[1]!'-'}
${seq[2]!'-'}
${seq[3]!'-'}
不存在处理
unsafe_expr?? or (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>
赋值操作
<#assign x += y>
${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 -->
<#if !(color == "red" || color == "green")>
The color is nor red nor green
</#if>
空格处理
忽略空格
${x + ":" + book.title?upper_case} 等价于 ${x+":"+book.title?upper_case}
注释
<#assign x <#-- A comment --> = 123 <#-- A comment -->>
<#function f(x <#-- A comment -->, y <#-- A comment -->)>
<#return <#-- A comment --> 1 <#-- A comment -->>
</#function>
<#assign someHash = {
"foo": 123, <#-- A comment -->
"bar": x <#-- A comment --> + 1,
<#-- A comment -->
"baaz": f(1 <#-- A comment -->, 2 <#-- A comment -->)
} <#-- A comment -->>
操作符优先级
其他
自定义指令
基本指令
通过<#macro>封装重复逻辑
定义
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
使用
<@greet></@greet>
带参数指令
定义
-- 单参数
<#macro greet person>
<font size="+2">Hello ${person}!</font>
</#macro>
-- 多参数
<#macro greet person color>
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
-- 参数默认值
<#macro greet person color="black">
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
使用
<@greet person="Fred"/> and <@greet person="Batman"/>
<@greet person="Fred" color="black"/>
嵌套内容
<#nested>
定义
-- 单次嵌套
<#macro border>
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</tr></td></table>
</#macro>
-- 多次嵌套
<#macro do_thrice>
<#nested>
<#nested>
<#nested>
</#macro>
<@do_thrice>
Anything.
</@do_thrice>
-- 带本地变量
<#macro repeat count>
<#local y = "test">
<#list 1..count as x>
${y} ${count}/${x}: <#nested>
</#list>
</#macro>
<@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat>
使用
<@border>The bordered text</@border>
循环处理
定义&使用
<#macro do_thrice>
<#nested 1>
<#nested 2>
<#nested 3>
</#macro>
<@do_thrice ; x> <#-- user-defined directive uses ";" instead of "as" -->
${x} Anything.
</@do_thrice>
输出
1 Anything.
2 Anything.
3 Anything.
变量定义
大多数变量都来自外部数据模型,但FreeMarker也是可以自定义变量的。
-- 普通变量
<#assign x = 1> <#-- create variable x -->
${x}
<#assign x = 2> <#-- replace variable x -->
${x}
<#assign x++> <#-- replace variable x -->
${x}
-- 本地变量
-- 循环变量
-- 全局变量
<#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"> <#-- replaces the plain var, not the loop var. -->
8. ${x} <#-- it still hides the plain var. -->
</#list>
9. ${x} <#-- now the new value of plain var. becomse visible -->
<#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>
${user} <#-- prints: Big Joe -->
<#assign user = "Joe Hider">
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->