freeMarker学习(三)

来源:互联网 发布:sql不包含某个字符串 编辑:程序博客网 时间:2024/06/06 14:17

一、自定义指令

1.1概述

自定义指令可以使用macro 指令来定义,这是模板设计者所关心的内容。Java 程序员若不想在模板中实现定义指令,而是在Java 语言中实现指令的定义,这时可以使用freemarker.template.TemplateDirectiveModel 类来扩展。
宏定义:宏是有一个变量名的模板片段。你可以在模板中使用宏作为自定义指令,这样就能进行重复性的工作。
例如,创建一个宏变量来打印大号的”Hello Joe!”。
<#macro greet><font size="+2">Hello Joe!</font></#macro>

macro 指令自身不打印任何内容,它只是用来创建宏变量,所以就会有一个名为greet 的变量。在<#macro greet>和</#macro>之间的内容(称为宏定义体)当使用它作为指令时将会被执行。你可以在FTL 标记中通过@代替#来使用自定义指令。使用变量名作为指令名。而且,自定义指令的结束标记也是需要的。
可以这样来使用greet 宏:<@greet></@greet>
因为<anything></anything>和<anything/>是相同的,你也可以使用单标记形式(如果你了解XML,那么就很容易理解了,它们是相似的):<@greet/>
宏能做的事情还有很多,因为在<#macro ...>和</#macro>之间的东西是模板片段,也就是说它可以包含插值(${...})和FTL 标签(如<#if ...>...</#if>)。
注意:
程序员通常将使用<@...>,这称为宏调用。

1.2参数

我们来改进greet 宏使之可以使用任意的名字,而不仅仅是”Joe”。为了实现这个目的,就要使用到参数。在macro 指令中,宏名称的后面位置是用来定义变量的。这里我们仅在greet 宏中定义一个变量,person:

<#macro greet person><font size="+2">Hello ${person}!</font></#macro>
那么就可以这样来使用这个宏:<@greet person="Fred"/> and <@greet person="Batman"/>
这和HTML 的语法是很相似的,它会打印出:
<font size="+2">Hello Fred!</font> and <font size="+2">Hello Batman!</font>

那么我们就看到了,宏参数的真实值是可以作为变量(person)放在宏定义体中的。
使用预定义指令时,参数的值(=号后边的值)可以是FTL 表达式。这样,不像HTML,"Fred"和"Batman"的引号就可以不用要了。<@greet person=Fred/>也意味着使用变量的值Fred 作为person 参数,而不是字符串"Fred"。当然参数值并不一定是字符串类型,也可以是数字,布尔值,哈希表,序列等…也可以在=号左边使用复杂表达式(比如someParam=(price + 50)*1.25)。

自定义指令可以有多个参数。如下所示,再添加一个新的参数color:
<#macro greet person color><font size="+2" color="${color}">Hello ${person}!</font></#macro>

那么,这个宏就可以这样来使用:<@greet person="Fred" color="black"/>
参数的顺序不重要,下面的这个和上面的含义也是相同的。
<@greet color="black" person="Fred"/>
当调用这个宏的时候,你仅仅可以使用在macro 指令中定义的参数(这个例子中是:person 和color)。那么当你尝试<@greet person="Fred" color="black"background="green"/>的时候就会发生错误,因为并没有在<#macro ...>中定义参数background。
同时也必须给出在宏中定义所有参数的值。如果你尝试<@greetperson="Fred"/>时也会发生错误,因为忘记指定color 的值了。很多情况下需要给一个参数指定一个相同的值,所以我们仅仅想在这个值发生变化后重新赋给变量。那么要达到这个目的,在macro 指令中必须这么来指定变量:param_name=usual_value。
例如,当没有特定值的时候,我们想要给color 赋值为"black",那么greet 指令就要这么来写:

<#macro greet person color="black"><font size="+2" color="${color}">Hello ${person}!</font></#macro>

现在,我们这么使用宏就可以了:<@greet person="Fred"/>,因为它和<@greet person="Fred" color="black"/>是相同的,这样参数color 的值就是已知的了。如果想给color 设置为”red” , 那么就写成:<@greetperson="Fred" color="red"/>,这时macro 指令就会使用这个值来覆盖之前设置的通用值,参数color 的值就会是”red”了。
根据FTL 表达式规则, 明白下面这一点是至关重要的,someParam=foo 和someParam="${foo}"是不同的。第一种情况,是把变量foo 的值作为参数的值来使用。第二种情况则是使用插值形式的字符串,那么参数值就是字符串了,这个时候,foo的值呈现为文本,而不管foo 是什么类型(数字,日期等)的。看下面这个例子:
someParam=3/4 和someParam="${3/4}"是不同的,如果指令需要someParam是一个数字值,那么就不要用第二种方式。切记不要改变这些。

1.3嵌套内容

自定义指令可以嵌套内容, 和预定义指令相似: <#if ...>nested content</#if>。比如,下面这个例子中是创建了一个可以为嵌套的内容画出边框:
<#macro border><table border=4 cellspacing=0 cellpadding=4><tr><td><#nested></td></tr></table></#macro>
<#nested>指令执行位于开始和结束标记指令之间的模板代码段。如果这样写:<@border>The bordered text</@border>
那么就会输出:
<table border=4 cellspacing=0 cellpadding=4><tr><td>The bordered text</td></tr></table>

nested 指令也可以多次被调用,例如:
<#macro do_thrice><#nested><#nested><#nested></#macro><@do_thrice>Anything.</@do_thrice>
输出:
Anything.
Anything.
Anything.
如果不使用nested 指令,那么嵌套的内容就会被执行,如果不小心将greet 指令写成了这样:
<@greet person="Joe">Anything.</@greet>
FreeMarker 不会把它视为错误,只是打印:<font size="+2">Hello Joe!</font>
嵌套的内容被忽略了,因为greet 宏没有使用nested 指令。
嵌套的内容可以是任意有效的FTL,包含其他的用户自定义指令,这样也是对的:
<@border><ul><@do_thrice><li><@greet person="Joe"/></@do_thrice></ul></@border>
将会输出:
<table border=4 cellspacing=0 cellpadding=4><tr><td><ul><li><font size="+2">Hello Joe!</font><li><font size="+2">Hello Joe!</font><li><font size="+2">Hello Joe!</font></ul></tr></td></table>

在嵌套的内容中,宏的局部变量是不可见的。为了说明这点,我们来看:
<#macro repeat count><#local y = "test"><#list 1..count as x>${y} ${count}/${x}: <#nested></#list></#macro><@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat>
将会打印:
test 3/1: ? ? ?test 3/2: ? ? ?test 3/3: ? ? ?

因为y,x 和count 是宏的局部(私有)变量,从宏外部定义是不可见的。此外不同的局部变量的设置是为每个宏自己调用的,所以不会导致混乱:
<#macro test foo>${foo} (<#nested>) ${foo}</#macro>
<@test foo="A"><@test foo="B"><@test foo="C"/></@test></@test>
将会打印出:
A (B (C () C) B) A


1.4宏和循环变量

自定义指令也可以有循环变量。比如我们来扩展先前例子中的do_thrice 指令,就可以拿到当前的循环变量的值。而对于预定义指令(如list),当使用指令(就像<#listfoos as foo>...</#list>中的foo)时,循环变量的名字是已经给定的,变量值的设置是由指令本身完成的。
<#macro do_thrice><#nested 1><#nested 2><#nested 3></#macro><@do_thrice ; x> <#-- 用户自定义指令 使用";"代替"as" -->${x} Anything.</@do_thrice>
将会输出:
1 Anything.2 Anything.3 Anything.
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!
在自定义指令的开始标签(分号之后)为循环变量指定不同的数字是没有问题的,而不能在nested 指令上使用。如果在分号之后指定的循环变量少,那么就看不到nested指令提供的最后的值,因为没有循环变量来存储这些值,下面的这些都是可以的:
<@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>

如果在分号后面指定了比nested 指令还多的变量,那么最后的循环变量将不会被创建(在嵌套内容中不会被定义)。


补充:
freemarker操作字符串(很常用)
1、substring(start,end)从一个字符串中截取子串
start:截取子串开始的索引,start必须大于等于0,小于等于end
end: 截取子串的长度,end必须大于等于0,小于等于字符串长度,如果省略该参数,默认为字符串长度。
例子:
${'str' substring(0)}结果为str
${'str' substring(1)}结果为tr
${'str' substring(2)}结果为r
${'str' substring(3)}结果为
${'str' substring(0,0)}结果为
${'str' substring(0,1)}结果为s
${'str' substring(0,2)}结果为st
${'str' substring(0,3)}结果为str

2、cap_first 将字符串中的第一个单词的首字母变为大写。
${'str' cap_first}结果为Str
3、uncap_first将字符串中的第一个单词的首字母变为小写。
${'Str' cap_first}结果为str
4、 capitalize将字符串中的所有单词的首字母变为大写
${'str' capitalize}结果为STR

5、 date,time,datetime将字符串转换为日期
例如:
<#assign date1="2009-10-12" date("yyyy-MM-dd")>
<#assign date2="9:28:20" time("HH:mm:ss")>
<#assign date3=" 2009-10-12 9:28:20" time("HH:mm:ss")>
${date1}结果为2009-10-12
${date2}结果为9:28:20
${date3}结果为2009-10-12 9:28:20
注意:如果指定的字符串格式不正确将引发错误。

6、ends_with 判断某个字符串是否由某个子串结尾,返回布尔值。
${"string" ends_with("ing") string} 返回结果为true
注意:布尔值必须转换为字符串才能输出

7、html 用于将字符串中的<、>、&和"替换为对应得&lt;&gt;&quot:&amp

8、index_of(substring,start)在字符串中查找某个子串,返回找到子串的第一个字符的索引,如果没有找到子串,则返回-1。
Start参数用于指定从字符串的那个索引处开始搜索,start为数字值。
如果start大于字符串长度,则start取值等于字符串长度,如果start小于0, 则start取值为0。
${"string" index_of("in") 结果为3
${"string" index_of("ab") 结果为-1

9、length返回字符串的长度 ${"string" length}结果为6

10、lower_case将字符串转为小写
${"STRING" lower_case}结果为string

11、upper_case将字符串转为大写
${"string" upper_case}结果为STRING

12、contains 判断字符中是否包含某个子串。返回布尔值
${"string" contains("ing") string} 结果为true
注意:布尔值必须转换为字符串才能输出

13、number将字符串转换为数字
${"111.11" number}结果为111.11

14、replace用于将字符串中的一部分从左到右替换为另外的字符串。
${"strabg" replace("ab","in")} 结果为string

15、split使用指定的分隔符将一个字符串拆分为一组字符串

<#list "This|is|split" split("|") as s>
${s}
</#list>
结果为:
This
is
split
获取image[]数组中的第一个元素:
<img src="${article.image.split(",")[0]}"  style="width:180px; height:120px; border-radius:50%; overflow:hidden;"> 

16、 trim 删除字符串首尾空格 ${" String " trim} 结果为String



























































0 0
原创粉丝点击