前人关于
FreeMarker
的总结
一宗罪:
freemarker
的变量必须有值,没有被赋值的变量就会抛出异常,那个黄黄的
freemarker
出错页面,真是让人看了太难过了。
freemarker
的
FAQ
上面冠冕堂皇的说,未赋值的变量强制抛错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误。但是实际的效果是:带来的是非常大的编程麻烦,程序里面几乎所有可能出现空值的变量统统需要加上
${xxx?if_exists}
,有些循环条件还需要写
if
判断,这样不但没有杜绝应该杜绝的错误,反而极大增加了编程的麻烦。
二宗罪:
freemarker
的
map
限定
key
必须是
string
,其他数据类型竟然无法操作!这一点就不讲了,
JavaEye
上面已经有人抱怨过了。连
Webwork
的开发人员
Pat Lightboy
都在抱怨这一点。
三宗罪:
freemarker
为了编程方便把不可序列化的东西往
session
里面放!
freemarker
支持在页面里面直接操作
Session
,
request
等,例如
${Session[...]}
,方便确实很方便,但是一旦需要做群集,就会报错。
但是这些小错误,个人认为无伤大雅,毕竟
WebWork
开发小组就是用
FreeMaker
的
,
那么我们在项目的时候肯会接触到
.ftl
文件,所以花几个单位时间学习下,还是必要的
现在来看看
FreeMaker
有哪些变量
·
Specify values directly
- Strings: "Foo" or 'Foo' or "It's /"quoted/"" or r"C:/raw/string" 最后一种用法要注意
- Numbers: 123.45
- Booleans: true, false
- Sequences: ["foo", "bar", 123.45], 1..100
- Hashes: {"name":"green mouse", "price":150} 这里注意,lookup name必须是String
·
Retrieving variables
- Top-level variables: ${user} action中的getter
- Retrieving data from a hash: user.name, user["name"]
- Retrieving data from a sequence: products[5]
- Special variable: .main(Normally you don't need to use special variables. They are for expert users.The complete list of special variables can be found in the reference.)
下面来看看关于
String
,
Sequence
,
Hash
的操作方法
·
String operations
- Interpolation (or concatenation): "Hello ${user}!" (or "Free" + "Marker")
- Getting a character: name[0]
有一种很典型的用法错误
<#if ${isBig}>Wow!#if>
,
Interpolations work only in text sections (e.g.
Hello ${name}!
) and in string literals
(e.g.
<#include "/footer/${company}.html">
)
you should use
the substring built-in;
里面关于String的处理应该是应有尽有了。
·
Sequence operations
- Concatenation: users + ["guest"]
- Sequence slice: products[10..19] or products[5..]
这里有几个关于
Sequence
的例子,值得看一下
<#assign x = ["red", 16, "blue", "cyan"]>
"blue": ${x?seq_contains("blue")?string("yes", "no")}
"yellow": ${x?seq_contains("yellow")?string("yes", "no")}
16: ${x?seq_contains(16)?string("yes", "no")}
"16": ${x?seq_contains("16")?string("yes", "no")}
|
|
The output will be:
"blue": yes
"yellow": no
16: yes
"16": no
|
|
seq_index_of
seq_last_index_of
还发现里面居然有排序功能
|
|
|
|
<#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort>
<#list ls as i>${i} #list>
|
|
|
|
|
|
|
<#assign ls = [
{"name":"whale", "weight":2000},
{"name":"Barbara", "weight":53},
{"name":"zeppelin", "weight":-200},
{"name":"aardvark", "weight":30},
{"name":"beetroot", "weight":0.3}
]>
Order by name:
<#list ls?sort_by("name") as i>
- ${i.name}: ${i.weight}
#list>
Order by weight:
<#list ls?sort_by("weight") as i>
- ${i.name}: ${i.weight}
#list>
|
|
最后还有一个函数非常之实用
<#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']>
<#list seq?chunk(4) as row>
<#list row as cell>${cell} #list>
#list>
<#list seq?chunk(4, '-') as row>
<#list row as cell>${cell} #list>
#list>
|
|
The output will be:
a b c d
e f g h
i j
a b c d
e f g h
i j - -
|
|
想想以前写网上商城购物系统的时候,从数据库里出来的数据都要把它们转换成几行几列的样子,算法都是自己写的,这种时代要过去了,呵呵
·
Hash operations
Concatenation:
passwords + {"joe":"secret42"}
这个没什么好说的了,就一个
Concatenation
·
Arithmetical calculations
:
(x * 1.5 + 10) / 2 - y % 100
有
5
个运算符
·
Comparison
:
x == y
,
x != y
,
x < y
,
x > y
,
x >= y
,
x <= y
,
x < y
, ...etc.
因为
FreeMarker
无法区分大于号和结尾符
>
的区别,所以最好用括号括起来
·
Logical operations
:
!registered && (firstVisit || fromEurope)
·
Method call
:
repeat("What", 3)
·
Missing value handler operators
:
- Default value: name!"unknown" or (user.name)!"unknown" or name! or (user.name)!
- Missing value test: name?? or (user.name)??
·
Parentheses
·
White-space in expressions FTL ignores superfluous white-space in expressions
·
Operator precedence 下面是运算符的优先权
Operator group |
Operators |
postfix operators |
[subvarName] [subStringRange] . ? (methodParams) expr!default expr! expr?? |
unary operators |
+expr -expr !expr |
multiplicative |
* / % |
additive |
+ - |
relational |
< > <= >= (and quivalents: gt, lt, etc.) |
equality |
== != (and equivalents: =) |
logical AND |
&& |
logical OR |
|| |
numerical range |
.. |
Escape sequence
|
Meaning
|
/"
|
Quotation mark (u0022)
|
/'
|
Apostrophe (a.k.a. apostrophe-quote) (u0027)
|
//
|
Back slash (u005C)
|
/n
|
Line feed (u000A)
|
/r
|
Carriage return (u000D)
|
/t
|
Horizontal tabulation (a.k.a. tab) (u0009)
|
/b
|
Backspace (u0008)
|
/f
|
Form feed (u000C)
|
/l
|
Less-than sign:
<
|
/g
|
Greater-than sign:
>
|
/a
|
Ampersand:
&
|
/{
|
Curly bracket:
{
|
/x
Code
|
Character given with its hexadecimal Unicode code (UCS code)
|
<#list 1..8 as x>
注意不要写成
[1..8]
${x}
#list>
/*-----------------
以下会出错
--------------------*/
<#list ["aa",3,true] as x>
${x}
#list>
<#list ["aa",3,[1,2]] as x>
${x}
#list>
Expecting a string, date or number here, Expression x is instead a freemarker.template.TemplateBooleanModel$2
可见,
list
中只能是
string, date or number
/*----------------------------------------------*/