freemarker 讲义

本文深入介绍了Freemarker模板引擎的各种类型支持、数据模型实现、模型接口操作及其注意事项。涵盖了标量、数字、布尔值、日期等多种数据类型的处理方法,并详细解释了容器、子程序、方法函数等功能的应用场景。
1. 类型
支持的类型 数据模型实现 模型接口 操作 注意
标量
字符串 SimpleScalar TemplateScalarModel "Hello ${user}!",name[0] ,
r"${"test"}" Actually,the name of this interface should be TemplateStringModel
数字 SimpleNumber TemplateNumberModel ${1+1}
${x?string.currency}
${x?string("0.###")} int,long,float,double,byte,short.
number_format:number,computer,currency,
percent,0.###,0
布尔 TemplateBooleanModel.TURE
TemplateBooleanModel.FALSE TemplateBooleanModel ${boo?string} ${boo}错误
${boo?string}正确
日期 SimpleDate TemplateDateModel ${today?date}
${today?string(“MM/dd/yyyy”)}
${“04/27/2012”?date}
${“04/27/2012”?date(“MM/dd/yyyy”)} 1.支持java.util.Date,
java.sql.{Date,Time,Timestamp}
2.如果是java.util.Date,输出日期时必须指定类型,?date,?time,?datetime,?string(“MM/dd/yyyy”)
3.可以通过全局配置date_format,time_format,datetime_format
容器
哈希表 SimpleHash TemplateHashModel {"name":"green mouse", "price":150}
user.name, user[“name”]
TemplateHashModelEx扩展了
Keys,values,size
可以实现了?keys,?values,?size
没有remove,只能加,不能减
数据模型会被包装成SimpleHash
序列 SimpleSequence TemplateSequenceModel ["foo", "bar", 123.45], 1..100
集 SimpleCollection TemplateCollectionModel
子程序
方法函数 自己定制的方法 TemplateMethodModel root.put("indexOf", new IndexOfMethod());

${indexOf("met", "something")} 1.BIMethod是【?】操作时所要实现功能的函数类,属于私有类
2.避免共享,避免有状态!

指令
系统只有两个实现IncludePage和SimpleTagDir
ectiveModel.
可以自己定制 TemplateDirectiveModel root.put("upper", new com.example.
UpperDirective());

<@upper>
To upper words
</@upper> 1.可以通过IncludePage实现另外一个servlet的调用
2.避免共享,避免有状态!
Java对象
Java bean StringModel
BeanModel TemplateScalarModel,
TemplateHashModel,
AdapterTemplateModel ${bean.getName()}
静态对象 StaticModels TemplateHashModel ${statics["java.lang.System"].currentTimeMillis()} 有三个安全等级:
EXPOSE_ALL,EXPOSE_SAFE,
EXPOSE_PROPERTIES_ONLY,EXPOSE_NOTHING
2.内建函数
处理字符串的内建函数
substring
cap_first 首字母大写
uncap_first
capitalize 每个单词首字母大写
upper_case 全部大写
lower_case
chop_linebreak 切断换行符
(如果在末尾没有换行符的字符串,那么可以换行,否则不改变字符串。)
date,time,datetime 日期,时间,时间日期
若日期字符串符合本地的日期格式 就无需传入“MM/dd/yyyy”这样的格式参数
<#assign test1 = "10/25/1995"?date("MM/dd/yyyy")>
<#assign test2 = "15:05:30"?time("HH:mm:ss")>
<#assign test3 = "1995-10-25 03:05 PM"?datetime("yyyy-MM-dd hh:mm a")>

<#assign test1 = "Oct 25, 1995"?date>
<#assign test2 = "3:05:30 PM"?time>
<#assign test3 = "Oct 25, 1995 03:05:00 PM"?datetime>

ends_with
html
HTML格式的转义文本(xhtml xml)
 <用&lt替换;
 >用&gt替换;
 &用&amp替换;
 "用&quot替换;
${user?html}
可以使用escape指令来节约很多输入,减少偶然错误的机会。

matches和groups
<#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
index_of
last_index_of
j_string Java语言规则的字符串转义
<#assign beanName = 'The "foo" bean.'>
String BEAN_NAME = "${beanName?j_string}";
将会打印
String BEAN_NAME = "The \"foo\" bean.";
js_string JavaScript语言规则的字符串转义
length
left_pad 距左边 right_pad
[${"a"?left_pad(5)}]
[ a]
[${""?left_pad(5, "-")}]
[----a]
contains
number 字符串转数字
replace
rtf 富文本
 \替换为\\
 {替换为\{
 }替换为\}
url URL转义
<#setting url_escaping_charset="UTF-8">
<#assign x = 'a/b c'>
${x?url}
a%2Fb%20c

<a href="foo.cgi?x=${x?url('utf-8')}">foo</a>

split
starts_with
trim 去掉字符串首尾的空格
word_list 词列表
<#assign words = " a bcd, . 1-2-3"?word_list>
<#list words as word>[${word}]</#list>
将会输出
[a][bcd,][.][1-2-3]
通用标记
i:大小写不敏感:不区分同一个字母大小写之间的差异。
f:仅仅是第一。也就是说,替换/查找等,只是第一次出现的东西。
r:查找的子串是正则表达式。

<#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
处理数字的内建函数
c 数字转字符
避免输出由于当前数字格式设置,本地化
${x?c}
string(当用作是数值类型时) 数字转字符串
$ {x?string}
${x?string.number}
${x?string.currency}
${x?string.percent}
${x?string.computer}
42
42
$42.00
4,200%
42
round,floor,ceiling 数字的舍入处理
floor:向负无穷进位
ceiling:向正无穷进位
处理日期的内建函数
string(当用作日期值时)日期转字符串
date,time,datetime (当使用日期值时)
iso_utc,iso_local,iso_utc_nz,iso_local_nz,iso_utc_m,iso_utc_m_nz内建函数族
utc,local:国际统一和本地当前时间
nz:是否显示时区偏移
处理布尔值的内建函数
string(当被用作是布尔值时) 转换布尔值为字符串
foo?string("yes", "no")
处理序列的内建函数
first 第一个变量
last 最后一个变量
seq_contanis 序列包含…
seq_index_of 第一次出现…时的位置
${names?seq_index_of("Joe", 0)}从第一个位子开始找
seq_last_index_of 最后一次出现..的位置
names?seq_last_index_of("Joe", 0)从第一个位置往前找
size 序列大小
sort 排序
可以字符串,数字,日期,布尔排序
sort_by 以…来排序
<#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>
如果想按降序来排列,后面再加?reverse
reverse 反转序列
chunk 区块
<#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>
输出:
a b c d
e f g h
i j - -
处理哈希表的内建函数(并不是所有的hash表都支持以下两种)
keys
values
3.模板语法及指令(宏)
if
<#if x == 1>
x is 1
<#if y == 1>
and y is 1 too
<#elseif y==2>
but y is not
</#if>
<#else>
x is not 1
<#if (y < 0)>
and y is less than 0
</#if>
</#if>
Switch
<#switch being.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
List
<#list seq as x>
${x}
<#if x = "spring"><#break></#if>
</#list>
Include
<#include path options>
Option 选项只有两个, encoding和parse(如果为false,当成普通文本)
<#include "/common/navbar.html" parse=false encoding="Shift_JIS">
本地化查找:
加载模板时,经常用本
地化环境匹配浏览器请求Web页面的语言偏好来请求模板。
 footer_en_US.ftl
 footer_en.ftl
 footer.ftl
import
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
可以通过configuration的addAutoImport做通用的引入操作
noparse
<#noparse>
<#list animals as being>
<tr><td>${being.name}<td>${being.price} Euros
</#list>
</#noparse>
不解析,作为普通文本
compress
<#assign x = " moo \n\n ">
(<#compress>
1 2 3 4 5
${moo}
test only
I said, test only
</#compress>)
输出为:
(1 2 3 4 5
moo
test only
I said, test only)
需要和剥离空白区分,compress会对生成后的文本进行压缩,比setWhitespaceStripping强势
escape,noescape
<#escape x as x?html>
From: ${mailMessage.From}
Subject: ${mailMessage.Subject}
<#noescape>Message: ${mailMessage.htmlFormattedBody}</#noescape>
...
</#escape>
Assign
多个定义
<#assign
seasons = ["winter", "spring", "summer", "autumn"]
test = test + 1
>
捕捉它的开始标记和结束标记中间生成的输出,成为它的值
<#macro myMacro>foo</#macro>
<#assign x>
<#list 1..3 as n>
${n} <@myMacro />
</#list>
</#assign>
Number of words: ${x?word_list?size}
${x}
global 指令
<#global name=value> 所有命名空间中都可以看到
<#setting name=value>
local 指令
<#local name=value>
仅仅在宏和方法的内部定义才会有作用。
setting 指令
<#setting name=value>
Locale
number_format,
boolean_format
date_format,time_format,datetime_format
time_zone
url_escaping_charset
classic_compatible
用户自定义指令
<@list items=["mouse", "elephant", "python"] title="Animals"/>
...
<#macro list title items>
<p>${title?cap_first}:
<ul>
<#list items as x>
<li>${x?cap_first}
</#list>
</ul>
</#macro>
输出为:
<p>Animals:
<ul>
<li>Mouse
<li>Elephant
<li>Python
</ul>
位置参数传递现在仅仅支持宏定义
macro,nested,return 指令
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>

参数省略示例:
<#macro test foo bar="Bar" baaz=-1>
Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>

macro示例:可变的参数数量:
<#macro img src extra...>
<img src="/context${src?html}"
<#list extra?keys as attr>
${attr}="${extra[attr]?html}"
</#list>
>
</#macro>
<@img src="/images/test.png" width=100 height=50 alt="Test"/>
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>
function,return 指令
<#function name param1 param2 ... paramN>
...
<#return returnValue>
...
</#function>
示例:
<#function avg x y>
<#return (x + y) / 2>
</#function>
${avg(10, 20)}
同样支持可变的参数数量
stop 指令
<#stop>

<#stop reason>
抛出StopException
ftl 指令
<#ftl param1=value1param2=value2…paramN=valueN>
ftl指令必须放在ftl文件的最上面。
一些设置(编码方式,空白剥离等)在这里给定的话就有最高的优先级,也就是说,它们直接作用于模板而不管其他任何FreeMarker配置的设置。
t,lt,rt 指令
t(整体削减):忽略本行中首和尾的所有空白。
lt(左侧削减):忽略本行中首部所有的空白。
rt(右侧削减):忽略本行中尾部所有的空白。
示例:
1 <#t>
2<#t>
3<#lt>
4
5<#rt>
6
输出:
1 23
4
5 6
attempt,recover 指令
<#attempt>
attempt block
<#recover>
recover block(代替出错内容)
</#attempt>
自定义方法和指令
Java程序员可以使用TemplateMethodModel接口在Java代码中实现自定义方法。
TemplateModel exec(java.util.List arguments)
Java程序员可以使用TemplateDirectiveModel接口在Java代码中实现自定义指令。
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body)
4.配置
配置信息可以被想象成3层(Configuration,Template,Environment),他们都实现configurable抽象
Configuration层:原则上设置配置信息时使用Configuration对象的setter方法
注意:在真正使用Configuration对象(通常在初始化应用程序时)之前来配置它,后面必须将其视为只读的对象。
Template层:这里不需要设置配置信息。应该在Template对象第一次被使用前就设置配置信息,然后就将Template对象视为是只读的。
Environment层:这里有两种配置方法:
1. Java api
env.setLocale(java.util.Locale.ITALY);
env.setNumberFormat("0.####");
2. 在模板中直接使用指令
<#setting locale="it_IT">
<#setting number_format="0.####">

所有配置项可以到configurable或api文档里面查

5.内部重要的类
Configuration
Freemarker api的入口
配置模板的加载器和缓存(setDirectoryForTemplateLoading, setServletContextForTemplateLoading, setClassForTemplateLoading)
管理共享变量
配置项
Template
通过FMParser创建rootElement
创建运行环境(environment)
配置项
Environment
执行模板(process),遍历模板中的rootElement
配置项
DefaultObjectWrapper
功能已经足够,继承了BeansWrapper的封装。
数据模型中的Collection和Map不被允许修改。可以通过一个java bean来实现
TemplateCache
通过templateLoader和storage来管理系统中的所有模板

CacheStorage
softStorage strongStorage MRUStorage

TemplateLoader(WebappTemplateLoader, FileTemplateLoader,ClassTemplateLoader)
功能:获取对象及修改时间
设置更新延迟,默认5秒(目前19楼主干上的是0)。类加载器不会注意到模板的更新。
在实际运行的环境中,类加载机制是首选用来加载模板的方法.。比从文件系统的特定目录位置加载安全而且简单
MultiTemplateLoader多加载器

TemplateElement(MixedContent,TextBlock,DollarVariable…)
模板(树)节点
执行输出(accept),TextBlock示例:
public void accept(Environment env)
throws IOException
{
env.getOut().write(text);
}
TemplateModel
所有能放到数据模型的对象都需要实现该接口

Expression
大部分的TemplateElement会有Expression实例作为成员对象。Expression也是一个树结构。
通过暴露getStringValue(env)和_getAsTemplateModel(env)来实现树的遍历

BuiltIn
the ? operator used to get the functionality of built-in unary operators
可以通过该类查找freemarker里所有的内建函数

FMParser
This class is generated by JavaCC from a grammar file
JavaCC(Java Compiler Compiler)是一个用JAVA开发的语法分析生成器。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值