变量定义
<#assign name1="北京" name2="上海" name3="广东"> 输出结果:${name1}、${name2}、${name3} <#assign str="你好"> 输出结果:${str} 输出结果:北京、上海、广东 输出结果:你好
<#assign num = 100 /> 适用类型:定义变量,支持计算和赋值
<#assign num = 101 /><br/> ${num * 10}<br/> ${num / 10}<br/> ${num + 10}<br/> ${num - 10}<br/> 输出结果: 1,010 10.1 111 91
list
<#list strList as item>
${item}
</#list>
map
<select id="selOrderStatus" name="orderStatus" class="form-control" > <option value="-1">全部</option> <#assign selected=''/> <#if orderStatusMap?exists> <#list orderStatusMap?keys as key> <#if (key == status?string)> <#assign selected='selected="selected"'/> <#else> <#assign selected=''/> </#if> <option ${selected} value="${key}">${orderStatusMap[key]}</option> </#list> </#if> </select>
switch
<#switch "星期三"> <#case "星期一"> 油焖大虾 <#break> <#case "星期二"> 炸酱面 <#break> <#default> 肯德基 </#switch>
输出结果:肯德基
${var!} 对 null 或者不存在的对象进行取值,可以设置默认值,例:${var!'我是默认值'} 即,有值时显示正常值,无值时显示默认值
${封装对象.属性}对封装对象进行取值,例:${User.name} 如果为空,也可以这么写:${order.orderId!"6666"};${order.getOrderCode()}
${var?html} 转义HTML内容 ${order.getOrderCode()?html}
string转数字
<#assign num="200.99"/> ${num?eval} <#if (num?eval >100)> 55557 </#if> 转换结果:200.99
数字转string
<#assign num=200.99/> ${num?string} <#if (num?string = "200.99")> true </#if>
字符串函数:
<#list "aa,bb,cc,dd"?split(",") as str> ${str} </#list> 输出结果:aa bb cc dd <br/> ${"hello world"?index_of("o")} 输出结果:4 <br/> ${"hello world"?last_index_of("l")} 输出结果:9 <br/> -${" gg "?trim}- 删除字符串首尾空格 输出结果:-gg- <br/> ${"GROUP VALUE"?lower_case} 小写 输出结果:group value <br/> ${"group value"?upper_case} 大写 输出结果:GROUP VALUE <br/> ${"group value"?cap_first} 第一个单词的首字母大写 输出结果:Group value <br/> ${"GROUP VALUE"?uncap_first} 第一个单词的首字母小写 输出结果:gROUP VALUE <br/> ${"group value"?capitalize} 所有单词的首字母大写 输出结果:Group Value <br/> ${"group value"?contains("val")?string} 判断字符中是否包含某个子串。返回布尔值 输出结果:true <br/> ${"group value"?starts_with("gro")?string} 判断某个字符串是否由某个子串开头,返回布尔值 输出结果:true <br/> ${"group value"?ends_with("lue")?string} 判断某个字符串是否由某个子串结尾,返回布尔值 输出结果:true <br/> ${"group value"?length} 判断字符中是否包含某个子串。返回布尔值 输出结果:11 <br/> ${"strabttuabg"?replace("ab","--")} 全部替换 输出结果: str--ttu--g <br/> ${"<font color = 'red'>我只是个菜单</font>"} ${order.getOrderCode()?html} 输出结果: <br/> ${"group"?substring(0)} ${"group"?substring(1)} ${"group"?substring(2)} ${"group"?substring(3)} 输出结果:group roup oup up <br/> ${"group"?substring(0,1)} ${"group"?substring(1,3)} ${"group"?substring(2,5)} 输出结果: g ro oup
${"abcde"?left_pad(10,"--")} 如果不足10个字符,以--在左边填充
输出结果:-----abcde
${"abcde"?right_pad(10,"--")} 如果不足10个字符,以--在右边填充
输出结果:abcde-----
数字格式化:
<br/> <br/> <br/> <#assign num=898> ${num?string(",##0.00")} 输出结果:898.00 <br/> <#assign num=0.1> ${num?string(",##0.00")} 输出结果:0.10 <br/> <#assign num=1234136.123> ${num?string(",##0.00")} 输出结果:1,234,136.12 <br/> <#assign num=1234136.775> ${num?string(",##0.00")} 输出结果:1,234,136.78 <br/> <#assign num=1234136.777> ${num?string(",##0.00")} 输出结果:1,234,136.78 <br/>------------------------------- <br/> <br/> <#assign num=898> ${num?string("0.00")} 输出结果:898.00 <br/> <#assign num=0.1> ${num?string("0.00")} 输出结果:0.10 <br/> <#assign num=1234136.123> ${num?string("0.00")} 输出结果:1234136.12 <br/> <#assign num=1234136.775> ${num?string("0.00")} 输出结果:1234136.78 <br/> <#assign num=1234136.777> ${num?string("0.00")} 输出结果:1234136.78 <br/>------------------------------- <br/> <br/> <#assign num=898> ${num?string("#.##")} 输出结果:898 <br/> <#assign num=0.1> ${num?string("#.##")} 输出结果:0.1 <br/> <#assign num=1234136.123> ${num?string("#.##")} 输出结果:1234136.12 <br/> <#assign num=1234136.775> ${num?string("#.##")} 输出结果:1234136.78 <br/> <#assign num=1234136.777> ${num?string("#.##")} 输出结果:1234136.78 <br/>------------------------------- <br/> <br/> ${1.2?string("0")} 输出结果:1 <br/> ${1.8?string("0")} 输出结果:2 <br/> ${1.5?string("0")} 输出结果:2 <br/> ${2.5?string("0")} 输出结果:2 <br/> ${1?string("000.00")} 输出结果:001.00 <br/> ${12.1?string("000.00")} 输出结果:012.10 <br/> ${123.456?string("000.00")} 输出结果:123.456 <br/>------------------------------- <br/> <br/> 舍去小数点后面的 ${1.8?int} ${1.5?int} ${1.4?int} 输出结果:1 1 1 <br/>------------------------------- <br/> <br/> <#assign num=1234136.777> ${num?string.number} 输出结果:1,234,136.777 <br/> ${num?string.currency} 输出结果:¥1,234,136.78 <br/> ${num?string.percent} 输出结果:123,413,678% <br/> <br/> <#setting number_format="currency"> <#assign x=5642.785> ${x} ${x?string} ${x?string.number} ${x?string.currency} ${x?string.percent} 输出结果:¥5,642.78 ¥5,642.78 5,642.785 ¥5,642.78 564,278% <br/>------------------------------- <br/> <br/> <#assign numList = [12,0.236,89,12.032,69.56,45.67,-0.561,-8.057,-89.56,4.69]/> <#list numList as num> ${num} ?round=${num?round} ?floor=${num?floor} ?ceiling=${num?ceiling}<br/> </#list> 输出结果: 12 ?round=12 ?floor=12 ?ceiling=12 0.236 ?round=0 ?floor=0 ?ceiling=1 89 ?round=89 ?floor=89 ?ceiling=89 12.032 ?round=12 ?floor=12 ?ceiling=13 69.56 ?round=70 ?floor=69 ?ceiling=70 45.67 ?round=46 ?floor=45 ?ceiling=46 -0.561 ?round=-1 ?floor=-1 ?ceiling=0 -8.057 ?round=-8 ?floor=-9 ?ceiling=-8 -89.56 ?round=-90 ?floor=-90 ?ceiling=-89 4.69 ?round=5 ?floor=4 ?ceiling=5
日期格式化
LocalDateTime 格式化 ${strDate?date}<br/> ${strDate?date("yyyy-MM-dd")}<br/> 输出结果: 2018-7-10 2018-7-10 <br/> LocalDateTime 格式化 ${(strDate?string)?replace("T"," ")?datetime("yyyy-MM-dd HH:mm:ss")}<br/> ${(strDate?string)?replace("T"," ")?date("yyyy-MM-dd")}<br/> ${(strDate?string)?replace("T"," ")?time("yyyy-MM-dd HH:mm:ss")}<br/> 输出结果: 2018-7-10 14:22:17 2018-7-10 14:22:17 <br/> <br/> 字符串格式化 ${"2012-06-17 01:08:18"?datetime("yyyy-MM-dd HH:mm:ss")}<br/> ${"2012-06-17 01:08:18"?date("yyyy-MM-dd")}<br/> ${"2012-06-17 01:08:18"?time("yyyy-MM-dd HH:mm:ss")}<br/> 输出结果: 2012-6-17 1:08:18 2012-6-17 1:08:18
long newDateLong=new Date().getTime();
<br/>
${newDateLong?number_to_datetime}
输出结果:2018-7-10 14:46:53
<br>
${newDateLong?number_to_date}
输出结果:2018-7-10
<br>
<br/>-------------------------------
<br/>
LocalDateTime localDateTime = LocalDateTime.now();
Objects.requireNonNull(localDateTime, "arg dt");
long localDateTimeLong = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
<br/>
${localDateTimeLong?number_to_datetime}
输出结果:2018-7-10 14:46:53
<br>
${localDateTimeLong?number_to_date}
输出结果:2018-7-10
<br/>
<br/>-------------------------------
<br/>
Objects.requireNonNull(localDate, "arg dt");
long localDateLong = localDate.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
<br/>
${localDateLong?number_to_datetime}
输出结果:2018-7-10 0:00:00
<br>
${localDateLong?number_to_date}
输出结果:2018-7-10
布尔值
<#assign foo=true> ${foo?string} ${foo?string("yes","no")} 输出结果: true yes
substring
${"group"?substring(0)}
${"group"?substring(1)}
${"group"?substring(2)}
${"group"?substring(3)}
输出结果:
group
roup
oup
up
${"group"?substring(0,1)}
${"group"?substring(1,3)}
${"group"?substring(2,5)}
输出结果:
g
ro
oup
lower_case将字符串转为小写
${"STRING"?lower_case}
输出结果:string
upper_case将字符串转为大写
${"string"?upper_case}
输出结果: STRING
cap_first 将字符串中的第一个单词的首字母变为大写。
${"group"?cap_first}
输出结果:Group
uncap_first将字符串中的第一个单词的首字母变为小写。
${"GROUP"?uncap_first}
输出结果:gROUP
capitalize 将字符串中的所有单词的首字母变为大写
${"group value"?capitalize}
输出结果:
Group Value
contains 判断字符中是否包含某个子串。返回布尔值
${"string"?contains("ing")?string}
输出结果:true
ends_with 判断某个字符串是否由某个子串结尾,返回布尔值。
${"string"?ends_with("ing")?string}
输出结果:true
index_of(substring,start)在字符串中查找某个子串,返回找到子串的第一个字符的索引,如果没有找到子串,则返回-1。
Start参数用于指定从字符串的那个索引处开始搜索,start为数字值。
如果start大于字符串长度,则start取值等于字符串长度,如果start小于0, 则start取值为0。
${"string"?index_of("in")}
${"string"?index_of("ab")}
输出结果:
3
-1
length返回字符串的长度
${"string"?length}
输出结果:6
number将字符串转换为数字
${"111.11"?number}
输出结果:111.11
replace 全部替换
${"strabttuabg"?replace("ab","--")}
输出结果: str--ttu--g
split使用指定的分隔符将一个字符串拆分为一组字符串
<#list "aa,bb,cc,dd"?split(",") as str>
${str}<br/>
</#list>
输出结果:
aa
bb
cc
dd
转载:
Freemarker内建函数 1.1 处理字符串的内建函数 1.1.1 substring 取子串 注意: 这个内建函数从 FreeMarker 2.3.7 开始可用。 概要 :exp?substring(from, toExclusive) ,也 可 以 作 为 exp?substring(from) 调用 一个字符串的子串。 from 是第一个字符开始的索引。它必须是一个数字而且至少是0, 而且要小于或等于 toExclusive ,否则错误就会中断模板的处理。 toExclusive 是 子串中最后一个字符之后的位置索引,换句话说,它比最后一个字符的索引大 1。它必须是 数字,至少是 0,要小于或等于字符串的长度,否则错误就会中止模板的处理。如果 toExclusive 被忽略了,那么它默认就是字符串的长度。如果参数不是整型的数字,那 么数值中只有整型的部分会被使用。 例如: 输出为: - ${'abc'?substring(0)} - ${'abc'?substring(1)} - ${'abc'?substring(2)} - ${'abc'?substring(3)} - ${'abc'?substring(0, 0)} - ${'abc'?substring(0, 1)} - ${'abc'?substring(0, 2)} - ${'abc'?substring(0, 3)} - ${'abc'?substring(0, 1)} - ${'abc'?substring(1, 2)} - ${'abc'?substring(2, 3)} 输出为: - abc - bc - c - - - a - ab - abc - a - b - c 1.1.2 cap_first 首字母大写 字符串中的第一个单词的首字母大写。更精确的“单词”的意思可以查看内建函数 word_list。 比如: ${" green mouse"?cap_first} ${"GreEN mouse"?cap_first} ${"- green mouse"?cap_first} 输出为: 在 "- green mouse" 的情形下,第一个单词是 - 。 1.1.3 uncap_first 首字母小写 这和 cap_first 是相反的。字符串第一个单词的首字母小写。 1.1.4 capitalize 首字母 大写 字符串的所有单词都大写。更精确的“单词”的意思可以查看内建函数 word_list。比如: 输出为: ${" green mouse"?cap_first} ${"GreEN mouse"?cap_first} 输出为: Green mouse GreEN mouse 1.1.5 chop_linebreak 切断换行符 如果在末尾没有换行符的字符串,那么可以换行,否则不改变字符串。 1.1.6 date ,time ,datetime 日期,时间,时间日期 字符串转换成日期值。建议指定一个确定格式个参数。比如: <#assign test1 ="10/25/1995"?date("MM/dd/yyyy")> <#assign test2 ="15:05:30"?time("HH:mm:ss")> <#assign test3 = "1995-10-25 03:05PM"?datetime("yyyy-MM-dd hh:mm a")> ${test1} ${test2} ${test3} 将会打印出(基于当地(语言)和其他设置决定输出)如下内容: Oct 25, 1995 3:05:30 PM Oct 25, 1995 3:05:00 PM 要注意日期根据 date_format , time_format 和 datetime_format 的设 置转换回字符串(对于日期转换成字符的更多内容请阅读:日期内建函数,日期插值)。这 和你在转换字符串到日期类型时使用什么格式没有关系。 如果你了解模板处理时默认的日期/时间/时间日期格式,你可以不用格式化参数: <#assign test1 = "Oct 25,1995"?date> <#assign test2 = "3:05:30PM"?time> <#assign test3 = "Oct 25, 199503:05:00 PM"?datetime> ${test1} ${test2} ${test3} 如果字符串不在适当的格式,当你尝试使用这些内建函数时,错误将会中断模板执行。 1.1.7 ends_with 以… 结尾 返回是否这个字符串以指定的子串结尾。比如 "redhead"?ends_with("head") 返回布尔值 true。而且 "head"?ends_with("head") 也返回 true。 1.1.8 html HTML 格式的转义文本 字符串按照 HTML 标记输出。也就是说,下面字符串将会被替代: < 用 < 替换; > 用 > 替换; & 用 & 替换; " 用 " 替换; 注意如果你想安全地插入一个属性,你必须在 HTML 模板中使用引号标记(是 " ,而不 是 ' )为属性值加引号: <input type=text name=uservalue="${user?html}"> 注意在 HTML 页面中,通常你想对所有插值使用这个内建函数。所以你可以使用 escape 指令来节约很多输入,减少偶然错误的机会。 1.1.9 group 分组 这个函数只和内建函数 matches 的结果使用。请参考 matches 函数。 1.1.10 index_of 索引所在位置 返回第一次字符串中出现子串时的索引位置。例如 "abcabc"?index_of("bc") 将会返回 1(不要忘了第一个字符的索引是 0)。而且,你可以指定开始搜索的索引位置:将 "abcabc"?index_of("bc",2) 会返回 4。这对第二个参数的数值没有限制:如果 它是负数,那就和是 0 是 ige 效果了,如果它比字符串的长度还大,那么就和它是字符串长 度那个数值是一个效果。小数会被切成整数。 如果第一个参数作为子串没有在该字符串中出现时(如果你使用了第二个参数,那么就 从给定的序列开始。),那么就返回-1. 1.1.11 j_string Java 语言规则的字符串转义 根据 Java 语言字符串转义规则来转义字符串,所以它很安全的将值插入到字符串类型 中。要注意它不会 在被插入的值的两侧添加引号;你需要在这里使用字符串值。 所有 UCS 编码下指向 0x20 的字符会被转义。当它们在 Java 语言中(比如 \n , \t 等) 没有专门的转义序列时,将会被用 UNICODE 进行转义替换( \uXXXX )。 例如: <#assign beanName = 'The "foo"bean.'> String BEAN_NAME ="${beanName?j_string}"; 将会打印: String BEAN_NAME = "The\"foo\" bean."; 1.1.12 js_string JavaScript 语言规则的字符串转义 根据 JavaScript 语言字符串转义规则来转义字符串,所以它很安全的将值插入到字符串 类型中。要注意,它不会 在被插入的值两侧添加引号;而是在字符串中间使用。 引号( " )和单引号( ' )要被转义。从 FreeMarker 2.3.1 开始,也要将 > 转义为 \> (为 了避免 </script> )。 所有在 UCS 编码下指向 0x20 的字符将会被转义。当它们在 JavaScript 中没有专用的转 义序列时(比如 \n , \t 等),它们会被 UNICODE 字符代替( \uXXXX )。 例如: <#assign user = "Big Joe's\"right hand\""> <script> alert("Welcome${user?js_string}!"); </script> 将会打印: <script> alert("Welcome Big Joe\'s \"righthand\"!"); </script> 1.1.13 json_string JSON 规则的字符串转义 根据 JSON 语言的字符串规则来转义字符串,所以在字符串中插入值是安全的。要注意 它不会 在被插入的值两侧添加引号;而是在字符串中间使用。 这不会转义 ' 字符,因为 JSON 字符串必须使用 " 来括起来。它会在 < 之后直接出现的 / (斜杠)字符转义为 \/ ,来避免 </script> 等。它也会在]]之后转义 > 字符为 \u003E , 来避免退出 XML 的 CDATA 段。 所有在 UCS 编码下指向0x20 的字符会被转义。当在 JSON 中没有专用的转义序列时(比 如 \n , \t 等),它们会被 UNICODE 字符代替( \uXXXX )。 1.1.14 last_index_of 最后的索引所在位置 返回最后一次(最右边)字符串中出现子串时的索引位置。它返回子串第一个(最左边) 字符所在位置的索引。例如 "abcabc"?last_index_of("ab") :将会返回 3。而且 你可以指定开始搜索的索引。例如: "abcabc"?last_index_of("ab", 2) ,将 会返回 0。要注意第二个参数暗示了子串开始的最大索引。对第二个参数的数值没有限制: 如果它是负数,那么效果和是零的一样,如果它比字符串的长度还大,那么就和它是字符串 长度那个数值是一个效果。小数会被切成整数。 如果第一个参数作为子串没有在该字符串中出现时(如果你使用了第二个参数,那么就 从给定的序列开始。),那么就返回-1. <#assign user = "Big Joe's\"right hand\""> <script> alert("Welcome${user?js_string}!"); </script> <script> alert("Welcome Big Joe\'s \"righthand\"!"); </script> 1.1.15 length 字符串长度 字符串中字符的数量 1.1.16 lower_case 小写形式 字符 串的 小 写形 式 。比 如 "GrEeNMoUsE?lower_case" 将会是 "green mouse" 。 1.1.17 left_pad 距左边 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。在 2.3 版本中是没有的。 如果它仅仅用 1 个参数,那么它将在字符串的开始插入空白,直到整个串的长度达到参 数指定的值。如果字符串的长度达到指定数值或者比指定的长度还长,那么就什么都不做了。 比如这样: 将会打印: 如果使用了两个参数,那么第一个参数表示的含义和你使用一个参数时的相同,第二个 参数指定用什么东西来代替空白字符。比如: [${""?left_pad(5)}] [${"a"?left_pad(5)}] [${"ab"?left_pad(5)}] [${"abc"?left_pad(5)}] [${"abcd"?left_pad(5)}] [${"abcde"?left_pad(5)}] [${"abcdef"?left_pad(5)}] [${"abcdefg"?left_pad(5)}] [${"abcdefgh"?left_pad(5)}] [ ] [ a] [ ab] [ abc] [ abcd] [abcde] [abcdef] [abcdefg] [abcdefgh] 将会打印: 第二个参数也可以是个长度比 1 大的字符串。那么这个字符串会周期性的插入,比如: 将会打印: 第二个参数必须是个字符串值,而且至少有一个字符。 1.1.18 right_pad 距右边 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。在 2.3 版本中是没有的。 这个和 left_pad 相同,但是它从末尾开始插入字符而不是从开头。 比如: [${""?left_pad(5,"-")}] [${"a"?left_pad(5,"-")}] [${"ab"?left_pad(5,"-")}] [${"abc"?left_pad(5,"-")}] [${"abcd"?left_pad(5,"-")}] [${"abcde"?left_pad(5,"-")}] 将会打印: [-----] [----a] [---ab] [--abc] [-abcd] [abcde] 第二个参数也可以是个长度比 1 大的字符串。那么这个字符串会周期性的插入,比如: [${""?left_pad(8,".oO")}] [${"a"?left_pad(8,".oO")}] [${"ab"?left_pad(8,".oO")}] [${"abc"?left_pad(8,".oO")}] [${"abcd"?left_pad(8,".oO")}] 将会打印: [.oO.oO.o] [.oO.oO.a] [.oO.oOab] [.oO.oabc] [.oO.abcd] 第二个参数必须是个字符串值,而且至少有一个字符。 1.1.19 contains 包含 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。在 2.3 版本中是没有的。 如果函数中的参数可以作为源字符串的子串,那么返回 true。 比如: <#if"piceous"?contains("ice")>It contains"ice"</#if> 将会输出: It contains "ice" 1.1.20 matches 匹配 这是一个“超级用户”函数。不管你是否懂正则表达式。 注意: 这个函数仅仅对使用 Java2 平台的 1.4 版本之后起作用。否则它会发生错误并中止模板 的处理。 这个函数决定了字符串是否精确匹配上模式。而且,它返回匹配的子串列表。返回值是 一个多类型的值: 布尔值:如果字符串精确匹配上模式返回true ,否则返回 false 。例如, "fooo"?matches('fo*') 是 true , 但 是 "fooo bar"?matches('fo*') 是 false 。 序列:字符串匹配子串的列表。可能是一个长度为 0 的序列。 比如: <#if"fxo"?matches("f.?o")>Matches.<#else>Does not match.</#if> <#assign res = "foo barfyo"?matches("f.?o")> <#if res>Matches.<#else>Doesnot match.</#if> Matching sub-strings: <#list res as m> - ${m} </#list> 将会打印: 如果正则表达式包含分组(括号),那么你可以使用内建函数 groups 来访问它们: 这会打印: matches 接受两个可选的标记参数,要注意它不支持标记fr ,而且也会忽略标记 r 。 <#if"fxo"?matches("f.?o")>Matches.<#else>Does not match.</#if> <#assign res = "foo bar fyo"?matches("f.?o")> <#if res>Matches.<#else>Doesnot match.</#if> Matching sub-strings: <#list res as m> - ${m} </#list> Matches. Does not match. Matching sub-strings: - foo - fyo <#assign res = "aa/rx;ab/r;"?matches("(\\w[^/]+)/([^;]+);")> <#list res as m> - ${m} is ${m?groups[1]} per ${m?groups[2]} </#list> - aa/rx; is aa per rx - ab/r; is ab per r matches 接受两个可选的标记参数,要注意它不支持标记fr ,而且也会忽略标记 r 。 1.1.21 number 数字格式 字符串转化为数字格式。这个数字必须是你在 FTL 中直接指定数值的格式。也就是说, 它必须以本地独立的形式出现,小数的分隔符就是一个点。此外这个函数认识科学记数法。 (比如 "1.23E6" , "1.5e-8" )。 如果这恶搞字符串不在恰当的格式,那么在你尝试访问这个函数时,错误会抛出并中止 模板的处理。 已知的问题:如果你使用比 Java2 平台 1.3 版本还早的版本,这个函数将不会被识别, 前缀和科学记数法都不会起作用。 1.1.22 replace 替换 在源字符串中,用另外一个字符穿来替换原字符串中出现它的部分。它不处理词的边界。 比如: ${"this is a caracarus"?replace("car", "bulldozer")} 将会打印: this is a bulldozer abulldozerus 替换是从左向右执行的。这就意味着: ${"aaaaa"?replace("aaa","X")} 将会打印: Xaa 如果 第 一 个 参 数 是 空 字 符 串 , 那 么 所 有 的 空 字 符 串 将 会 被 替 换 , 比 如 "foo"?replace("","|"),就会得到 "|f|o|o|" 。 replace 接受一个可选的标记参数,作为第三个参数。 1.1.23 rtf 富文本 字符串作为富文本(RTF 文本),也就是说,下列字符串: \ 替换为 \\ { 替换为 \{ } 替换为 \} 1.1.24 url URL 转义 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。在 2.3 版本中是没有的。 在 URL 之后的字符串进行转义。这意味着,所有非 US-ASCII 的字符和保留的 URL 字符 将会被 %XX 形式来转义。例如: <#assign x = 'a/b c'> ${x?url} 输出将是(假设用来转义的字符集是 US-ASCII 兼容的字符集): a%2Fb%20c 注意它会转义所有保留的 URL 字符( / , = , & 等),所以编码可以被用来对查询参数的 值进行,比如: <ahref="foo.cgi?x=${x?url}&y=${y?url}">Click here...</a> 注意: 上面的没有 HTML 编码( ?htm )是必要的,因为 URL 转义所有保留的 HTML 编码。但 是要小心:通常引用的属性值,用普通引号( " )包括,而不是单引号( ' ),因为单引号是 不被 URL 转义的。 为了进行 URL 转义,必须要选择字符集,它被用来计算被转义的部分( %XX )。如果你 是 HTML 页面设计者,而且你不懂这个,不要担心:程序员应该配置 FreeMarker,则它默认 使用恰当的字符集(程序员应该多看看下面的内容)。如果你是一个比较热衷于技术的人, 那么你也许想知道被 url_escaping_charset 设置的指定字符集,它可以在模板的 执行时间设置(或者,更好的是,由程序员之前设置好)。例如: <#-- This will use the charset specified by theprogrammers before the template execution has started. --> <ahref="foo.cgi?x=${x?url}">foo</a> <#-- Use UTF-8 charset for URL escapingfrom now: --> <#settingurl_escaping_charset="UTF-8"> <#-- This will surely use UTF-8 charset--> <ahref="bar.cgi?x=${x?url}">bar</a> 此外,你可以明确地指定一个为单独 URL 转义的字符集,作为内建函数的参数: <ahref="foo.cgi?x=${x?url('ISO-8895-2')}">foo</a> 如果内建函数 url 没有参数,那么它会使用由 url_escaping_charset 设置的 字符集。这个设置应该被软件设置,包括 FreeMarker (比如一个 Web 应用框架),因为它不 会被 默 认 设 置 为 null 。 如 果 它 没 有 被 设 置 , 那 么 FreeMarker 退 回 使 用 output_encoding 的设置,这个也会被默认设置,所以它也是又软件设置的。如果 output_encoding 也没有被设置,那么没有参数的内建函数 url 将不会被执行,二 期它会引起运行时错误。当然,有参数的 url 函数将会执行。 用 setting 指令在模板中设置 url_escaping_charset 是可能的。至少在真 实的 MVC 应用中,这是一个不好的实践行为。 output_encoding 不能由 setting 指令来设置,所以它应该是软件的工作。你可以阅读程序开发指南 / 其它 / 字符集问题来获取更多信息。 1.1.25 split 分割 它被用来根据另外一个字符串的出现将原字符串分割成字符串序列。比如: <#list"someMOOtestMOOtext"?split("MOO") as x> - ${x} </#list> 将会打印: - some - test - text 既然已经假设所有分隔符的出现是在新项之前,因此: <#list"some,,test,text,"?split(",") as x> - "${x}" </#list> 将会打印: - "some" - "" - "test" - "text" - "" split 函数接受一个可选的标记参数作为第二个参数。 1.1.26 starts_with 以… 开头 如果 字 符 串 以 指 定 的 子 字 符 串 开 头 , 那 么 返 回 true 。 比 如 "redhead"?starts_with("red")返 回 布 尔 值 true , 而 且 "red"?starts_with("red")也返回 true。 1.1.27 string (当被用作是字符串值时) 什么也不做,仅仅返回和其内容一致的字符串。例外的是,如果值是一个多类型的值(比 如同时有字符串和序列两种),那么结果就只是一个简单的字符串,而不是多类型的值。这 可以被用来防止多种人为输入。 1.1.28 trim 修整字符串 去掉字符串首尾的空格。例如: 输出是: 1.1.29 upper_case 大写形式 字符串的大写形式。比如 "GrEeN MoUsE" 将会是 "GREENMOUSE" 。 1.1.30 word_list 词列表 包含字符串词的列表,并按它们在字符串中的顺序出现。词是连续的字符序列,包含任 意字符,但是不包括空格。比如: <#assign words = " a bcd, .1-2-3"?word_list> <#list words asword>[${word}]</#list> 将会输出: [a][bcd,][.][1-2-3] 1.1.31 xhtml XHTML 格式 字符串作为 XHTML 格式文本输出,下面这些: < 替换为 < > 替换为 > & 替换为 & " 替换为 " ' 替换为 ' 这个函数和 xml 函数的唯一不同是 xhtml 函数转义 ' 为 ' ,而不是 ' , 但是一些老版本的浏览器不正确解释 ' 。 1.1.32 xml XML 格式 字符串作为 XML 格式文本输出,下面这些: < 替换为 < > 替换为 > (${" green mouse "?trim}) (green mouse) <#assign words = " a bcd, .1-2-3"?word_list> <#list words asword>[${word}]</#list> [a][bcd,][.][1-2-3] & 替换为 & " 替换为 " ' 替换为 ' 1.1.33 通用标记 很多字符串函数接受一个可选的被称为“标记”的字符串参数。在这些字符串中,每一 个字符都影响着内建函数行为的一个特定方面。比如,字母 i 表示内建函数不应该在同一 个字母的大小写上有差异。标记中字母的顺序并不重要。 下面是标记字母的完整列表: i :大小写不敏感:不区分同一个字母大小写之间的差异。 f :仅仅是第一。也就是说,替换/查找等,只是第一次出现的东西。 r :查 找的 子串 是正 则表 达式 。FreeMarker 使用 变化 的正 则表 达式 ,在 http://java.sun.com/j2se/1.4.1/docs/api/java/util/regex/Pattern.html中描述。 只有 你使用 Java2 平台的 1.4 版本以后,标记才会起作用。否则它会发生错误导致模板 处理停止。 m :正则表达式多行模式。在多行模式下,表达式^ 和 $ 仅仅匹配前后,分别是一 行结尾或者是字符串的结束。默认这些表达式仅仅匹配整个字符串的开头和结尾。 注意 ^ 和 $ 不会匹配换行符本身。 s :启用正则表达式的 do-tall 模式(和 Perl 的单行模式一样)。在do-tall 模式下, 表达式 . 匹配任意字符串,包括行结束符。默认这个表达式不匹配行结束符。 c :在正则表达式中许可空白和注释。 示例: <#assign s = 'foo bAr baar'> ${s?replace('ba', 'XY')} i: ${s?replace('ba', 'XY', 'i')} if: ${s?replace('ba', 'XY', 'if')} r: ${s?replace('ba*', 'XY', 'r')} ri: ${s?replace('ba*', 'XY', 'ri')} rif: ${s?replace('ba*', 'XY', 'rif')} 这会输出: foo bAr XYar i: foo XYr XYar if: foo XYr baar r: foo XYAr XYr ri: foo XYr XYr rif: foo XYr baar 这是内建函数使用通用标记的表格,哪些支持什么样的标记。 内建函数 i (忽略大小写) r (正则表达式) m (多行模式) s(dot-all模式) c (whitesp和注释) f (仅第一个) replace 是 是 只和 r 只和 r 只和 r 是 split 是 是 只和 r 只和 r 只和 r 否 match 是 忽略 是 是 是 否 1.2 处理数字的内建函数 相关的 FAQs:如果你有和 1,000,000 或 1 000 000 而不是 1000000 类似的东西,或者是 3.14 而不是 3,14 的东西,反之亦然,请参考FAQ 中相关内容,也要注意内建函数 c 的所有 内容。 1.2.1 c 数字转字符 注意: 这个内建函数从 FreeMarker 2.3.3 以后开始存在。 这个函数将数字转换成字符串,这都是对计算机来说的,而不是对用户。也就是说,它 根据程序语言的用法来进行格式化,这对于 FreeMarker 的所有本地数字格式化设置来说是 独立的。它通常使用点来作为小数分隔符,而且它从来不用分组分隔符(像 3,000,000),指 数形式(比如 5E20),多余的在开头或结尾的 0(比如 03 或 1.0),还有+号(比如+1)。它最 多在小数点后打印 16 位,因此数值的绝对值小于 1E-16 将会显示为 0。这个函数非常严格, 因为作为默认(像 ${x} 这样)数字被本地(语言,国家)特定的数字格式转换为字符串, 这是让用户来看的(比如 3000000 可能会被打印为 3,000,000)。当数字不对用户打印时(比 如,对于一个数据库记录 ID,用作是 URL 的一部分,或者是 HTML 表单中的隐藏域,或者 打印 CSS/JavaScript 的数值文本),这个函数必须被用来打印数字(也就是使用 ${x?c} 来代 替 ${x} ),否则输出可能由于当前数字格式设置,本地化(比如在一些国家中,小数点不 是点,而是逗号)和数值(像大数可能被分组分隔符“损坏”)而损坏。 1.2.2 string (当用作是数值类型时) 数字转字符串 将一个数字转换成字符串。它使用程序员已经指定的默认格式。你也可以明确地用这个 函数再指定一个数字格式,这在后面会展示。 有四种预定义的数字格式: computer , currency , number 和 percent 。这 些格式的明确含义是本地化(国家)指定的,受Java 平台安装环境所控制,而不是 FreeMarker, 除了 computer ,用作和函数 c 是相同的格式。你可以这样来使用预定义的格式: <#assign x=42> ${x} ${x?string} <#-- the same as ${x} --> ${x?string.number} ${x?string.currency} ${x?string.percent} ${x?string.computer} 如果你本地是 US English,那么就会生成: 42 42 42 $42.00 4,200% 42 前三个表达式的输出是相同的,因为前两个表达式是默认格式,这里是数字。你可以使 用一个设置来改变默认设置: <#settingnumber_format="currency"> <#assign x=42> ${x} ${x?string} <#-- the same as ${x} --> ${x?string.number} ${x?string.currency} ${x?string.percent} 现在会输出: $42.00 $42.00 42 $42.00 4,200% 因为默认的数字格式被设置成了“货币”。 除了这三种预定义格式,你可以使用 Java 中数字格式语法写的任意的数字格式 (http://java.sun.com/j2se/1.4/docs/api/java/text/DecimalFormat.html): <#assign x = 1.234> ${x?string("0")} ${x?string("0.#")} ${x?string("0.##")} ${x?string("0.###")} ${x?string("0.####")} ${1?string("000.00")} ${12.1?string("000.00")} ${123.456?string("000.00")} ${1.2?string("0")} ${1.8?string("0")} ${1.5?string("0")} <-- 1.5,rounded towards even neighbor ${2.5?string("0")} <-- 2.5,rounded towards even neighbor ${12345?string("0.##E0")} 输出这些: 1 1.2 1.23 1.234 1.234 001.00 012.10 123.46 1 2 2 <-- 1.5, rounded towards even neighbor 2 <-- 2.5, rounded towards even neighbor 1.23E4 在金融和统计学中,四舍五入都是根据所谓的一半原则,这就意味着对最近的“邻居” 进行四舍五入,除非离两个邻居距离相等,这种情况下,它四舍五入到偶数的邻居。如果你 注意看 1.5 和 2.5 的四舍五入的话,这在上面的示例中是可以看到的,两个都被四舍五入到 2,因为 2 是偶数,但 1 和 3 是奇数。 除了 Java 小数 语 法 模 式 之 外 , 你 可 以 编 写 如 ${aNumber?string("currency")} 这 样 的 代 码 , 它 会 做 和 ${aNumber?string.currency} 一样的事情。 正如之前展示的预定义格式,默认的数字格式也可以在模板中进行设置: <#settingnumber_format="0.##"> ${1.234} 输出这个: 1.23 要注意数字格式是本地化敏感的: <#setting locale="en_US"> US people write:${12345678?string(",##0.00")} <#setting locale="hu"> Hungarian people write:${12345678?string(",##0.00")} 输出这个: US people write: 12,345,678.00 Hungarian people write: 12 345 678,00 1.2.3 round,floor,ceiling 数字的舍入 处理 注意: 内建函数 round 从 FreeMarker 2.3.13 版本之后才存在。 使用确定的舍入法则,转换一个数字到整数: round :返回最近的整数。如果数字以.5 结尾,那么它将进位(也就是说向正无 穷方向进位) floor :返回数字的舍掉小数后的整数(也就是说向服务穷舍弃) ceiling :返回数字小数进位后的整数(也就是说向正无穷进位) 示例: <#assign testlist=[ 0, 1, -1, 0.5, 1.5, -0.5, -1.5, 0.25, -0.25, 1.75, -1.75]> <#list testlist as result> ${result} ?floor=${result?floor} ?ceiling=${result?ceiling} ?round=${result?round} </#list> 打印: 0 ?floor=0 ?ceiling=0 ?round=0 1 ?floor=1 ?ceiling=1 ?round=1 -1 ?floor=-1 ?ceiling=-1 ?round=-1 0.5 ?floor=0 ?ceiling=1 ?round=1 1.5 ?floor=1 ?ceiling=2 ?round=2 -0.5 ?floor=-1 ?ceiling=0 ?round=0 -1.5 ?floor=-2 ?ceiling=-1 ?round=-1 0.25 ?floor=0 ?ceiling=1 ?round=0 -0.25 ?floor=-1 ?ceiling=0 ?round=0 1.75 ?floor=1 ?ceiling=2 ?round=2 -1.75 ?floor=-2 ?ceiling=-1 ?round=-2 这些内建函数在分页处理时也许有用。如果你仅仅想展示数字的舍入形式,那么你应该 使用内建函数 string 和 numer_format 设置。 1.3 处理日期的内建函数 1.3.1 string (当用作日期值时)日期转字符串 这个内建函数以指定的格式转换日期类型到字符串类型。(当默认格式由 FreeMarker 的 date_format , time_format 和datetime_format 设置来支配时是很好的选 择,那么你就不需要使用这个内建函数了。) 格式可以是预定义格式中的一种,或者你可以指定明确的格式化模式。 预定义的格式是 short , medium , long 和 full ,它们定义了冗长的结果文本输 出。例如,如果输出的本地化是 U.S. English,而且时区是 U.S. Pacific,那么下面的代码: ${openingTime?string.short} ${openingTime?string.medium} ${openingTime?string.long} ${openingTime?string.full} ${nextDiscountDay?string.short} ${nextDiscountDay?string.medium} ${nextDiscountDay?string.long} ${nextDiscountDay?string.full} ${lastUpdated?string.short} ${lastUpdated?string.medium} ${lastUpdated?string.long} ${lastUpdated?string.full} 将会打印这样的内容: 12:45 PM 12:45:09 PM 12:45:09 PM CEST 12:45:09 PM CEST 4/20/07 Apr 20, 2007 April 20, 2007 Friday, April 20, 2007 4/20/07 12:45 PM Apr 20, 2007 12:45:09 PM April 20, 2007 12:45:09 PM CEST Friday, April 20, 2007 12:45:09 PM CEST short , medium , long 和 full 的精确含义是以当前本地(语言)设置为主的。 此外,它不是由 FreeMarker 确定的,而是由你运行 FreeMarker 的 Java 平台实现的。 对于包含日期和时间两部分的日期类型,你可以分别指定日期和时间部分的长度: ${lastUpdated?string.short_long} <#--short date, long time --> ${lastUpdated?string.medium_short} <#--medium date, short time --> 将会输出: 4/8/03 9:24:44 PM PDT Apr 8, 2003 9:24 PM 注意 ?string.short 和 ?string.short_short 是相 同 的, ?string.medium 和 ?string.medium_medium 是相同的,等等。 警告! 不幸的是,由于 Java 平台的限制,你可以在数据模型中保存日期变量,那里 FreeMarker 不能决定变量是否存储的是日期部分(年,月,日),还是时间部分(时,分,秒,毫秒), 还是两者都有。这种情况下,当你编写如 ${lastUpdated?string.short} ,或简 单的 ${lastUpdated} 时 FreeMarker 不知道如何来显示日期,因此模板会中止执行并抛 出错误。要阻止这些发生,你可以使用内建函数 ?date , ?time 和 ?datetime 来帮助 FreeMarker。比如${lastUpdated?datetime?string.short} 。要询问程序员 数据模型中确定的变 量是否 有这个问 题,或通 常使用 内建函数 ?date , ?time 和 ?datetime 来处理。 要代替使用预定义的格式,你可以使用 ?string(pattern_string) 来精确指定 格式的模式。这个模式使用 Java 日期格式的语法。比如: ${lastUpdated?string("yyyy-MM-ddHH:mm:ss zzzz")} ${lastUpdated?string("EEE, MMM d,''yy")} ${lastUpdated?string("EEEE, MMMM dd,yyyy, hh:mm:ss a '('zzz')'")} 将会输出: 2003-04-08 21:24:44 Pacific Daylight Time Tue, Apr 8, '03 Tuesday, April 08, 2003, 09:24:44 PM (PDT) 注意: 不像预定义 格式 ,你不 能和 精确 的给 定模式 使用 内建 函数 ?date , ?time 和 ?datetime ,因为使用这个模式你就告诉 FreeMarker 来显示哪部分的日期。然而, FreeMarker 将盲目地信任你,如果你显示的部分不存在于变量中,所以你可以显示“干扰”。 比如 ${openingTime?string("yyyy-MM-dd hh:mm:ss a")} , 而 openingTime 中只存储了时间,将会显示1970-01-01 09:24:44 PM 。 定义模式的字符串也可以是 "short" , "medium" , "short_medium" 等。这和 你使 用 预 定 义 格 式 语 法 :someDate?string("short") 和 someDate?string.short 是相同的。 也可以参考:模板开发指南/模板/插值中的日期部分。 1.3.2 date ,time ,datetime (当使用日期值时) 这些内建函数用来指定日期变量中的哪些部分被使用: date :仅仅年,月和日的部分被使用。 ime :仅仅时,分,秒和毫秒的部分被使用。 datetime :日期和时间量部分都使用。 在最佳情况下,你不需要使用这些内建函数。不幸的是,由于 Java 平台上的技术限制, FreeMarker 有时不能发现日期中的哪一部分在使用(也就是说,仅仅年+月+日在使用,或仅 仅时+分+秒+毫秒在使用,或两种都用);询问程序员哪些变量会有这个问题。如果 FreeMarker 不得不执行需要这些信息的操作-比如用文本显示日期-但是它不知道哪一部分在使用,它会 以错误来中止运行。这就是你不得不使用内建函数的时候了。比如,假设 openingTime 是一个有这样问题的变量: <#assign x = openingTime> <#-- noproblem can occur here --> ${openingTime?time} <#-- without ?timeit would fail --> <#-- For the sake of betterunderstanding, consider this: --> <#assign openingTime = openingTime?time> ${openingTime} <#-- this will work now--> 这些函数的另外一种用法:来截短日期。比如: Last updated: ${lastUpdated} <#-- assumethat lastUpdated is a date-time value --> Last updated date: ${lastUpdated?date} Last updated time: ${lastUpdated?time} 将会输出这样的东西: Last updated: 04/25/2003 08:00:54 PM Last updated date: 04/25/2003 Last updated time: 08:00:54 PM 如果 ? 的左边是字符串,那么这些内建函数会将字符串转换为日期变量。(参考处理字 符串的内建函数 date) 1.3.3 iso_... 内建函数族 这些内建函数转换日期,时间或时间日期值到字符串,并遵循 ISO 8601 的扩展格式。 这些 内 建 函 数 有 很 多 表 形 式 : iso_utc , iso_local , iso_utc_nz , iso_local_nz , iso_utc_m ,iso_utc_m_nz 等。名称的构成由下列单词顺序组 成,每部分由一个_(下划线)分隔开: 1. iso (必须的) 2. 是 utc 或 local 的二者之一(必须的(除了给定一个参数,这个后面再来说)):来 指定你想根据 UTC 来打印日期或根据当前时区来打印。当前时区是根据 FreeMarker 的 设置项 time_zone 来确定的,它通常是由程序员在模板外配置的(当然它也可以在 模板内设置,比如使用 <#setting time_zone="America/New_York"> )。 3. h, m 或 ms (可选的):时间部分的精度。当忽略的时候,就默认设置到秒的精度(比 如 12:30:18 )。 h 表示小时的精度(比如 12 ), m 表示分钟的精度(比如 12:30 ), ms 就表示毫秒的精度( 12:30:18.25,这里表示 250 毫秒)。要注意当使用 ms 时, 毫秒会显示为百分制的形式(遵循标准)而且不会去尾到 0 秒。因此,如果毫秒的部分 变成 0 的话,整个的毫秒的部分就会被忽略掉了。同时也要注意毫秒的部分是由一个点 来分隔的,而不是逗号(遵循 Web 约定和 XML Schema 的日期/时间格式)。 4. nz (可选的):如果有的话,时区偏移(比如 +02:00 或 -04:30 或 Z )就不会显示 出来了。否则是会显示出来的,仅仅对日期值有效(因为有时区偏移的日期在 ISO 8601:2004 中没有出现)。从 FreeMarker2.3.19 版开始,出于遵守 XML Schema 的日期/ 时间格式的考虑,偏移通常包含分钟。 示例: <#assign x = openingTime> <#-- noproblem can occur here --> ${openingTime?time} <#-- without ?timeit would fail --> <#-- For the sake of betterunderstanding, consider this: --> <#assign openingTime =openingTime?time> ${openingTime} <#-- this will work now--> Last updated: ${lastUpdated} <#-- assumethat lastUpdated is a date-time value --> Last updated date: ${lastUpdated?date} Last updated time: ${lastUpdated?time} Last updated: 04/25/2003 08:00:54 PM Last updated date: 04/25/2003 Last updated time: 08:00:54 PM 可能输出为(基于当前的时间和时区): <#assign aDateTime = .now> <#assign aDate = aDateTime?date> <#assign aTime = aDateTime?time> Basic formats: ${aDate?iso_utc} ${aTime?iso_utc} ${aDateTime?iso_utc} Different accuracies: ${aTime?iso_utc_ms} ${aDateTime?iso_utc_m} Local time zone: ${aDateTime?iso_local} 可能输出为(基于当前的时间和时区): Basic formats: 2011-05-16 21:32:13Z 2011-05-16T21:32:13Z Different accuracies: 21:32:13.868Z 2011-05-16T21:32Z Local time zone: 2011-05-16T23:32:13+02:00 还有另外一组 iso_... 内建函数形式,你可从名称中以忽略掉 local 或 utc ,但 是要指定时区作为内建函数的参数。比如 <#assign aDateTime = .now> ${aDateTime?iso("UTC")} ${aDateTime?iso("GMT-02:30")} ${aDateTime?iso("Europe/Rome")} The usual variations are supported: ${aDateTime?iso_m("GMT+02")} ${aDateTime?iso_m_nz("GMT+02")} ${aDateTime?iso_nz("GMT+02")} 可能输出为(基于当前的时间和时区) 2011-05-16T21:43:58Z 2011-05-16T19:13:58-02:30 2011-05-16T23:43:58+02:00 The usual variations are supported: 2011-05-16T23:43+02:00 2011-05-16T23:43 2011-05-16T23:43:58 如果该时区参数不能被解释,那么模板处理就会出错并且终止。 参数也可以是 java.util.TimeZone 对象类型(会返回 Java 中方法或在数据模 型中的值),而不仅仅是字符串。 1.4 处理布尔值的内建函数 1.4.1 string (当被用作是布尔值时) 转换布尔值为字符串 转换布尔值到字符串。你也以两种方式来使用: 以 foo?string :这样会使用代表 true 和 false 值的默认字符串来转换布尔值为字符 串。默认情况,true 被翻译为 "true" ,而 false 被翻译为 "false" 。如果你用 FreeMarker 来生成源代码,这是很有用的,因为这个值不是对本地化(语言,国家)敏感的。为了改变 这些默认的字符串,你可以使用 boolean_format 设置。注意,如果变量是多类型的 变量,也就是有布尔值和字符串,那么变量的字符串值会被返回。 以 foo?string("yes", "no") :如果布尔值是 true,这会返回第一个参数(这 里是: "yes" ),否则就返回第二个参数(这里是: "no" )。注意返回的的值是一个字符 串;如果参数是数字类型,首先它会被转换成字符串。 1.5 处理序列的内建函 数 1.5.1 first 第一个子变量 序列的第一个子变量。如果序列为空,那么模板处理将会中止。 1.5.2 last 最后一个子变量 序列的最后一个子变量。如果序列为空,那么模板处理将会中止。 2011-05-16T21:43:58Z 2011-05-16T19:13:58-02:30 2011-05-16T23:43:58+02:00 The usual variations are supported: 2011-05-16T23:43+02:00 2011-05-16T23:43 2011-05-16T23:43:58 1.5.3 seq_contanis 序列包含… 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。而在 2.3 版本中不存在。 注意: seq_ 前缀在这个内建函数中是需要的,用来和contains 区分开。 contains 函 数用来在字符串中查找子串(因为变量可以同时当作字符串和序列)。 辨别序列中是否包含指定值。它包含一个参数,就是来查找的值。比如: <#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")} 输出是: "blue": yes "yellow": no 16: yes "16": no 为了查找值,这个函数使用了 FreeMarker 的比较规则(就像你使用的 == 运算符),除 了比较两个不同类型的值,或 FreeMarker 不支持的类型来比较,其他都不会引起错误,只 是为认为两个值不相等。因此,你可以使用它来查找标量值(也就是字符串,数字,布尔值, 或日期/时间类型)。对于其他类型结果通常都是 false 。 对于容错性,这个函数还对 collections 起作用。 1.5.4 seq_index_of 第一次出现… 时的位置 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。而在 2.3 版本中不存在。 注意: seq_ 前缀在这个内建函数中是需要的,用来和index_of 区分开。 index_of 函 数用来在字符串中查找子串(因为变量可以同时当作字符串和序列)。 返回序列中第一次出现该值时的索引位置,如果序列不包含指定的值时返回 -1 。要查 找的值作为第一个参数。比如这个模板: <#assign colors = ["red","green", "blue"]> ${colors?seq_index_of("blue")} ${colors?seq_index_of("red")} ${colors?seq_index_of("purple")} 将会输出: 2 0 -1 为了查找值,这个函数使用了 FreeMarker 的比较规则(就像你使用的 == 运算符),除 了比较两个不同类型的值,或 FreeMarker 不支持的类型来比较,其他都不会引起错误,只 是为认为两个值不相等。因此,你可以使用它来查找标量值(也就是字符串,数字,布尔值, 或日期/时间类型)。对于其他类型结果通常是 -1 。 搜索开始的地方可以由第二个可选的参数来确定。如果在同一个序列中相同的项可以多 次出现时,这是很有用的。第二个参数的数值没有什么限制:如果它是负数,那么就和它是 零的效果一样,而如果它是比序列长度还大的数,那么就和它是序列长度值的效果一样。小 数值会被切成整数。比如: <#assign names = ["Joe","Fred", "Joe", "Susan"]> No 2nd param:${names?seq_index_of("Joe")} -2: ${names?seq_index_of("Joe",-2)} -1: ${names?seq_index_of("Joe",-1)} 0: ${names?seq_index_of("Joe",0)} 1: ${names?seq_index_of("Joe",1)} 2: ${names?seq_index_of("Joe",2)} 3: ${names?seq_index_of("Joe",3)} 4: ${names?seq_index_of("Joe",4)} 将会输出: No 2nd param: 0 -2: 0 -1: 0 0: 0 1: 2 2: 2 3: -1 4: -1 1.5.5 seq_last_index_of 最后一次出现.. 的位置 注意: 这个内建函数从 FreeMarker 2.3.1 版本开始可用。而在 2.3 版本中不存在。 注意: seq_ 前缀在这个内建函数中是需要的,用来和last_index_of 区分开。 last_index_of 用于在字符串中搜索子串(因为一个变量可以同时是字符串和序列)。 返回序列中最后一次出现值的索引位置,,如果序列不包含指定的值时返回 -1 。也就是 说,和 seq_index_of 相同,只是在序列中从最后一项开始向前搜索。它也支持可选的 第二个参数来确定从哪里开始搜索的索引位置。比如: <#assign names = ["Joe","Fred", "Joe", "Susan"]> No 2nd param:${names?seq_index_of("Joe")} -2: ${names?seq_index_of("Joe",-2)} -1: ${names?seq_index_of("Joe",-1)} 0: ${names?seq_index_of("Joe",0)} 1: ${names?seq_index_of("Joe",1)} 2: ${names?seq_index_of("Joe",2)} 3: ${names?seq_index_of("Joe",3)} 4: ${names?seq_index_of("Joe",4)} 将会输出这个: No 2nd param: 2 -2: -1 -1: -1 0: 0 1: 0 2: 2 3: 2 4: 2 1.5.6 reverse 反转序列 序列的反序形式。 1.5.7 size 序列大小 序列中子变量的数量(作为一个数值)。假设序列中至少有一个子变量,那么序列 s 中 最大的索引是 s?size - 1 (因为第一个子变量的序列是 0)。 1.5.8 sort 排序 以升序方式返回。(要使用降序排列时,使用它之后还要使用 reverse 内建函数)这 仅在子变量都是字符串时有效,或者子变量都是数字,或者子变量都是日期值(日期,时间, 或日期+时间),或者所有子变量都是布尔值时(从 2.3.17 版本开始)。如果子变量是字符串, 它使用本地化(语言)的具体单词排序(通常是大小写不敏感的)。比如: <#assign ls = ["whale","Barbara", "zeppelin", "aardvark", "beetroot"]?sort> <#list ls as i>${i} </#list> 将会打印(至少是 US 区域设置): aardvark Barbara beetroot whale zeppelin 1.5.9 sort_by 以… 来排序 返回由给定的哈希表子变量来升序排序的哈希表序列。(要降序排列使用这个内建函数 后还要使用 reverse 内建函数)这个规则和内建函数 sort 是一样的,除了序列中的子 变量必须是哈希表类型,而且你不得不给哈希变量的命名,那会用来决定排序顺序。比如: <#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") asi> - ${i.name}: ${i.weight} </#list> Order by weight: <#list ls?sort_by("weight") asi> - ${i.name}: ${i.weight} </#list> 将会打印(至少是 US 区域设置): Order by name: - aardvark: 30 - Barbara: 53 - beetroot: 0.3 - whale: 2000 - zeppelin: -200 Order by weight: - zeppelin: -200 - beetroot: 0.3 - aardvark: 30 - Barbara: 53 - whale: 2000 如果你用来排序的子变量的层次很深(也就是说,它是子变量的子变量的子变量,以此 类推),那么你可以使用序列来作为参数,它指定了子变量的名字,来向下引导所需的子变 量。比如: <#assign members = [ {"name": {"first":"Joe", "last": "Smith"}, "age": 40}, {"name": {"first":"Fred", "last": "Crooger"}, "age": 35}, {"name": {"first":"Amanda", "last": "Fox"}, "age":25}]> Sorted by name.last: <#list members?sort_by(['name', 'last'])as m> - ${m.name.last}, ${m.name.first}: ${m.age}years old </#list> 将会打印(至少是 US 区域设置): Sorted by name.last: - Crooger, Fred: 35 years old - Fox, Amanda: 25 years old - Smith, Joe: 40 years old 1.5.10 chunk 区块 注意: 这个内建函数从 FreeMarker 2.3.3 版本以后可用。 这个 内建 函数 分割 序列 到多 个大 小为 函数 的第 一个 参数 给定 的序 列( 就 像 mySeq?chunk(3) )。结果是包含这些序列的一个序列。最后一个序列可能比给定的大 小要小,处分第二个参数也给定了(比如 mySeq?chunk(3, '-') ),那个就是用来填 充最后一个序列,以达到给定的大小。比如: <#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> 这会输出: a b c d e f g h i j a b c d e f g h i j - - 这个函数通常在输出的序列中使用表格/柱状的格式。当被用于 HTML 表格时,第二个 参数通常是 "\xA0" (也就是不换行的空格代码,也就是我们所知的“nbsp”),所以空 TD 的边界就不会不显示。 第一个参数必须是一个数字,而且至少是 1.如果这个数字不是整数,那么它会被静默地 去掉小数部分(也就是说 3.1 和 3.9 都会被规整为 3)。第二个参数可以是任意类型的值。 1.6 处理哈希表的内建函数 1.6.1 keys 键的集合 一个包含哈希表中查找到的键的序列。注意并不是所有的哈希表都支持这个(询问程序 员一个指定的哈希表是否允许这么操作)。 <#assign h ={"name":"mouse", "price":50}> <#assign keys = h?keys> <#list keys as key>${key} = ${h[key]};</#list> 输出: name = mouse; price = 50; 因为哈希表通常没有定义子变量的顺序,那么键名称的返回顺序就是任意的。然而,一 些哈希表维持一个有意义的顺序(询问程序员指定的哈希表是否是这样)。比如,由上述 {...} 语法创建的哈希表保存了和你指定子变量相同的顺序。 1.6.2 值的集合 一个包含哈希表中子变量的序列。注意并不是所有的哈希表都支持这个(询问程序员一 个指定的哈希表是否允许这么操作)。 至于返回的值的顺序,和函数 keys 的应用是一样的;看看上面的叙述就行了。 1.7 处理节点(XML )的内建函数 注意由这些内建函数返回的变量是由用于节点变量的实现生成的。意思就是返回的变量 可以有更多的特性,附加于它这里的状态。比如,由内建函数 children 返回的序列和 XML DOM 节点也可以被用作是哈希表或字符串,这在第三部分 XML 处理指南中有解释。 1.7.1 children 子节点序列 一个包含该节点所有子节点(也就是直接后继节点)的序列。 XML:这和特殊的哈希表的键 * 几乎是一样的。除了它返回所有节点,而不但是元素。 所以可能的子节点是元素节点,文本节点,注释节点,处理指令节点等,而且还可能是属性 节点。属性节点排除在序列之外。 1.7.2 parent 父节点 在节点树中,返回该节点的直接父节点。根节点没有父节点,所以对于根节点,表达式 node?parent?? 的值就是 false 。 XML:注意通过这个函数返回的值也是一个序列(当你编写 someNode[".."] 时, 和 XPath 表达式 .. 的结果是一样的)。也要注意属性节点,它返回属性所属的元素节点,尽 管属性节点不被算作是元素的子节点。 1.7.3 root 根节点 该节点所属节点树的根节点。 XML:根据 W3C,XML 文档的根节点不是最顶层的元素节点,而是文档本身,是最高元 素的父节点。例如,如果你想得到被称为是 foo 的 XML(所谓的“文档元素”,不要和“文 档”搞混了)的最高元素,那么你不得不编写 someNode?root.foo 。如果你仅仅写了 someNode?root ,那么你得到的是文档本身,而不是文档元素。 1.7.4 ancestors 祖先节点 一个包含所有节点祖先节点的序列,以直接父节点开始,以根节点结束。这个函数的结 果也是一个方法,你可以用它和元素的完全限定名来过滤结果。比如以名称 section 用 node?ancestors("section") 来获得所有祖先节点的序列, 1.7.5 node_name 节点名称 当被“访问”时,返回用来决定哪个用户自定义指令来调用控制这个节点的字符串。可 以参见 visit 和 recurse 指令。 XML:如果节点是元素或属性,那么字符串就会是元素或属性的本地(没有前缀)名字。 否则,名称通常在节点类型之后以 @ 开始。可以参见 XML 处理指南中 2.2 节的形式化描述。 要注意这个节点名称与在 DOM API 中返回的节点名称不同;FreeMarker 节点名称的目标是 给要处理节点的用户自定义指令命名。 1.7.6 node_type 节点类型 描述节点类型的字符串。FreeMarker 没有对节点类型定义准确的含义;它依赖于变量是 怎么建模的。也可能节点并不支持节点类型。在这种情形下,该函数就返回未定义值,所以 你就不能使用返回值。(你可以用 node?node_type?? 继续检查一个节点是否是支持类 型属性) XML : 可 能 的 值 是"attribute" , "text" , "comment" , "document_fragment" ,"document" , "document_type" , "element", "entity" ,"entity_reference" , "notation" , "pi" 。注意没有 "cdata" 类型,因为 CDATA 被认为是普通文本元素。 1.7.7 node_namespace 节点命名空间 返回节点命名空间的字符串。FreeMarker 没有为节点命名空间定义准确的含义;它依赖 于变量是怎么建模的。也可能节点没有定义任何节点命名空间。这种情形下,该函数应该返 回未定义的变量(也就是 node?node_namespace?? 的值是 false ),所以你不能使 用这个返回值。 XML : 这 种 情 况 下 的 XML , 就 是 XML 命 名 空 间 的 URI ( 比 如 "http://www.w3.org/1999/xhtml" )。如果一个元素或属性节点没有使用 XML 命名空间,那么这个函数就返回一个空字符串。对于其他 XML 节点这个函数返回未定义的 变量。 1.8 很少使用的和专家级的内建函数 这些是你通常情况下不应该使用的内建函数,但是在特殊情况下(调试,高级宏)它们 会有用。如果你需要在普通页面模板中使用这些函数,你可能会重新访问数据模型,所以你 不要使用它们。 1.8.1 byte ,double ,float ,int ,long ,short 返回一个包含原变量中相同值的 SimpleNumber ,但是在内部表示值中使用了 java.lang.Type 。如果方法被重载了,这是有用的,或者一个 TemplateModel 解包器在自动选择适合的 java.lang.* 类型有问题时。注意从 2.3.9 版本开始,解包器 有本质上改进,所以你将基本不会使用到这些内建函数来转换数字类型了,除非在重载方法 调用中来解决一些含糊的东西。 内建函数 long 也可以用于日期, 时间和时 间日期 类型的 值来获取 返回为 java.util.Date.getTime() 的值。如果你不得不调用使用long 类型时间戳的 Java 方法时,这是非常有用的。这个转换不是自动进行的。 1.8.2 number_date ,number_to_time ,number_to_datetime 它们被用来转换数字(通常是 Java 的 long 类型)到日期,时间或时间日期类型。这 就使得它们和 Java 中的 new java.util.Date(long) 是一致的。那也就是说,现在 数字可以被解释成毫秒数进行参数传递。数字可以是任意内容和任意类型,只要它的值可以 认为是 long 就行。如果数字不是完整的,那么它就会根据“五入”原则进行进位。这个 转换不是自动进行的。 示例: ${1305575275540?number_to_datetime} ${1305575275540?number_to_date} ${1305575275540?number_to_time} 输出就会是像这样的(基于当前的本地化设置和时区): May 16, 2011 3:47:55 PM May 16, 2011 3:47:55 PM 1.8.3 eval 求值 这个函数求一个作为 FTL 表达式的字符串的值。比如 "1+2"?eval 返回数字 3。 1.8.4 has_content 是否有内容 如果变量(不是 Java 的 null )存在而且不是“空”就返回 true ,否则返回 false 。 “空”的含义靠具体的情形来决定。它是直观的常识性概念。下面这些都是空:长度为 0 的字符串,没有子变量的序列或哈希表,一个已经超过最后一项元素的集合。如果值不是字 符串,序列,哈希表或集合,如果它是数字,日期或布尔值(比如 0 和 false 是非空的), 那么它被认为是非空的,否则就是空的。注意当你的数据模型实现了多个模板模型接口,你 可能会得到不是预期的结果。然而,当你有疑问时你通常可以使用 expr!?size > 0 或 expr!?length > 0 来代替 expr?has_content 。 这个函数是个特殊的函数,你可以使用像默认值操作符那样的圆括号手法。也就是说, 你可 以 编 写product.color?has_content 和 (product.color)?has_content 样的代码。第一个没有控制当product 为空 的情形,而第二个控制了。 1.8.5 interpret 将字符串解释为 FTL 模板 这个函数解释字符串作为 FTL 模板,而且返回一个用户自定义指令,也就是当应用于任 意代码块中时,执行模板就像它当时被包含一样。例如: <#assign x=["a","b", "c"]> <#assign templateSource =r"<#list x as y>${y}</#list>"> <#-- Note: That r was needed so that the${y} is not interpreted above --> <#assign inlineTemplate = templateSource?interpret> <@inlineTemplate /> 输出为: abc 正如你看到的, inlineTemplate 是用户自定义指令,也就是当被执行时,运行当 时使用 interpret 函数生成的模板。 你也可以在两个元素的序列中应用这个函数。这种情况下序列的第一个元素是模板源代 码,第二个元素是内联模板的名字。在调试时它可以给内联模板一个确定的名字,这是很有 用的。所以你可以这么来写代码: <#assign inlineTemplate = [templateSource, "myInlineTemplate"]?interpret> 在上述的模板中,要注意给内联模板一个名字没有及时的效果,它仅仅在你得到错误报 告时可以得到额外的信息。 1.8.6 is_... 判断函数族 这些内建函数用来检查变量的类型,然后根据类型返回或。下面是 is_... 判断函数 族的列表: 内建函数 如果值是… 时返回 true is_string 字符串 is_number 数字 is_boolean 布尔值 is_date 日期(所有类型:仅日期,仅时间和时间日期) is_method 方法 is_transform 变换 is_macro 宏 is_hash 哈希表 is_hash_ex 扩展的哈希表(也就是支持 ?keys 和 ?values ) is_sequence 序列 is_collection 集合 is_enumerable 序列或集合 is_indexable 序列 is_directive 指令的类型(比如宏,或 TemplateDirectiveModel , TemplateTransformModel 等) is_node 节点 1.8.7 namespace 命名空间 这个函数返回和宏变量关联的命名空间(也就是命名空间的入口哈希表)。你只能和宏 一起来用它。 1.8.8 new 创建TemplateModel 实现 这是用来创建一个确定 TemplateModel 实现的变量的内建函数。 在 ? 的左边你可以指定一个字符串,是 TemplateModel 实现类的完全限定名。结 果是调用构造方法生成一个方法变量,然后将新变量返回。 比如: 对于更多的关于构造方法参数被包装和如何选择重载的构造方法信息,请阅读:程序开 发指南/其它/Bean 包装器部分内容。 这个内建函数可以是出于安全考虑的,因为模板作者可以创建任意的 Java 对象,只要 它们实现了 TemplateModel 接口,然后来使用这些对象。而且模板作者可以触发没有 实现 TemplateModel 接口的类的静态初始化块。你可以(从 FreeMarker 2.3.17 版开始) 限制 这 个 内 建 函 数 对 类 的 访 问 , 通 过 使 用 Configuration.setNewBuiltinClassResolver(TemplateClassRes olver) 或设置new_builtin_class_resolver 。参考 Java API 文档来获取详细信 息。如果您允许并不是很可靠的用户上传模板,那么你一定要关注这个问题。 <#-- Creates an user-defined directivebe calling the parameterless constructor of the class--> <#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()> <#-- Creates an user-defined directivebe calling the constructor with one numerical argument--> <#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)> 对于更多的关于构造方法参数被包装和如何选择重载的构造方法信息,请阅读:程序开 发指南/其它/Bean 包装器部分内容。 这个内建函数可以是出于安全考虑的,因为模板作者可以创建任意的 Java 对象,只要 它们实现了 TemplateModel 接口,然后来使用这些对象。而且模板作者可以触发没有 实现 TemplateModel 接口的类的静态初始化块。你可以(从 FreeMarker 2.3.17 版开始) 限制 这 个 内 建 函 数 对 类 的 访 问 , 通 过 使 用 Configuration.setNewBuiltinClassResolver(TemplateClassRes olver) 或设置new_builtin_class_resolver 。参考 Java API 文档来获取详细信 息。如果您允许并不是很可靠的用户上传模板,那么你一定要关注这个问题。 --------------------- 作者:R鲜森 来源:CSDN 原文:https://blog.csdn.net/sinat_32366329/article/details/78888222 版权声明:本文为博主原创文章,转载请附上博文链接!
浙公网安备 33010602011771号