freemarker中文手册
FreeMarker概述 l FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写 l FreeMarker被设计用来生成HTML Web页面,特别是基于MVC模式的应用程序l 虽然FreeMarker具有一些编程的能力,但通常由Java程序准备要显示的数据,由FreeMarker生成页面,通过模板显示准备的数据(如下图) l FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件 l FreeMarker 与容器无关,因为它并不知道 HTTP或 Servlet;FreeMarker 同样可以应用于非Web应用程序环境 l FreeMarker更适合作为Model2框架(如Struts)的视图组件,你也可以在模板中使用JSP标记库 l FreeMarker是免费的 1、通用目标 l 能够生成各种文本HTML、XML、RTF、Java源代码等等 l 易于嵌入到你的产品中轻量级;不需要Servlet环境 l 插件式模板载入器可以从任何源载入模板,如本地文件、数据库等等 l 你可以按你所需生成文本保存到本地文件;作为Email发送;从 Web应用程序发送它返回给Web浏览器 2、强大的模板语言 l 所有常用的指令include、if/elseif/else、循环结构 l 在模板中创建和改变变量 l 几乎在任何地方都可以使用复杂表达式来指定值 l 命名的宏,可以具有位置参数和嵌套内容 l 名字空间有助于建立和维护可重用的宏库,或者将一个大工程分成模块,而不必担心名字冲突 l 输出转换块在嵌套模板片段生成输出时,转换HTML转义、压缩、语法高亮等等;你可以定义自己的转换 3、通用数据模型 l FreeMarker不是直接反射到Java对象,Java对象通过插件式对象封装,以变量方式flexpaper.studylead.com在模板中显示 l 你可以使用抽象(接口)方式表示对象(JavaBean、XML 文档、SQL 查询结果集等等),告诉模板开发者使用方法,使其不受技术细节的打扰 4、为Web准备 l 在模板语言中内建处理典型Web相关任务(如HTML转义)的结构 l 能够集成到Model2 Web应用框架中作为JSP的替代 l 支持JSP标记库 l 为MVC模式设计分离可视化设计和应用程序逻辑;分离页面设计员和程序员 5、智能的国际化和本地化 l 字符集智能化(内部使用UNICODE) l 数字格式本地化敏感 l 日期和时间格式本地化敏感 l 非US字符集可以用作标识(如变量名) l 多种不同语言的相同模板 6、强大的XML处理能力 l 和指令(2.3版本)用于递归遍历XML树 l 在模板中清楚和直觉的访问XML对象模型 FreeMarker设计指南1 1、快速入门 (1)模板 数据模型 输出 l FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念 l 他们是分工劳动的设计者专注于表示创建 HTML文件、图片、Web页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据 l 经常会遇到的问题是在 Web 页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的 l 在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码 l 下面是一个例子 Welcome flexpaper.studylead.com Welcome {user} Our latest product {latestProduct.name} l 这个例子是在简单的HTML中加入了一些由{}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template) l 至于user、latestProduct.url和latestProduct.name来自于数据模型(data model) l 数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成 l 模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型 l 下面是一个可能的数据模型 root | - user “Big Joe“ | - latestProduct | - url “products/greenmouse.html“ | - name “green mouse“ l 数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而user、url和name看作是文件,url和name文件位于latestProduct目录中(这只是一个比喻,实际并不存在) l 当FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出 Welcome Welcome Big Joe flexpaper.studylead.com Our latest product green mouse (2)数据模型 l 典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子 root | - animals | | | - mouse | | | | | - size “small“ | | | | | - price 50 | | | - elephant | | | | | - size “large“ | | | | | - price 5000 | | | - python | | | - size “medium“ | | | - price 4999 | - test “It is a test“ | flexpaper.studylead.com - whatnot | - because “don t know“ l 类似于目录的变量称为hashes,包含保存下级变量的唯一的查询名字 l 类似于文件的变量称为scalars,保存单值 l scalars 保存的值有两种类型字符串(用引号括起,可以是单引号或双引号)和数字(不要用引号将数字括起,这会作为字符串处理) l 对scalars的访问从root开始,各部分用“.”分隔,如animals.mouse.price l 另外一种变量是sequences,和 hashes类似,只是不使用变量名字,而使用数字索引,如下面的例子 root | - animals | | | - 1st | | | | | - name “mouse“ | | | | | - size “small“ | | | | | - price 50 | | | - 2nd | | | | | - name “elephant“ | | | | | - size “large“ | | | | | - price 5000 | | | - 3rd | | flexpaper.studylead.com | - name “python“ | | | - size “medium“ | | | - price 4999 | - whatnot | - fruits | - 1st “orange“ | - 2nd “banana“ l 这种对scalars的访问使用索引,如animals[0].name (3)模板 l 在FreeMarker模板中可以包括下面三种特定部分 {}称为interpolations,FreeMarker会在输出时用实际值进行替代 FTL 标记(FreeMarker 模板语言标记)类似于 HTML 标记,为了与 HTML标记区分,用开始(有些以开始,在后面叙述) 注释包含在(而不是)之间 l 下面是一些使用指令的例子 if指令 Pythons are cheaper than elephants today. Pythons are not cheaper than elephants today. list指令 We have these animals NamePrice {being.name}{being.price} Euros flexpaper.studylead.com 输出为 We have these animals NamePrice mouse50 Euros elephant5000 Euros python4999 Euros include指令 Test page Test page Blah blah... 一起使用指令 We have these animals NamePrice {being.name} flexpaper.studylead.com {being.price} Euros FreeMarker设计指南3 3、模板 (1)整体结构 l 模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合 文本直接输出 Interpolation由{和},或{和}来限定,计算值替代输出 FTL标记FreeMarker指令,和 HTML标记类似,名字前加予以区分,不会输出 注释由限定,不会输出 l 下面是以一个具体模板例子 [BR] [BR] Welcome[BR] [BR] [BR] [BR] Welcome {user}[BR] We have these animals[BR] [BR] [BR] {being.name} for {being.price} Euros[BR] [BR] flexpaper.studylead.com [BR] [BR] l [BR]是用于换行的特殊字符序列 l 注意事项 FTL区分大小写,所以list是正确的FTL指令,而List不是;{name}和{NAME}是不同的 Interpolation只能在文本中使用 FTL标记不能位于另一个FTL标记内部,例如 bar ... 注释可以位于FTL标记和Interpolation内部,如下面的例子 Welcome {user }[BR] We have these animals[BR] [BR] animals as being[BR] ... 多余的空白字符会在模板输出时移除 (2)指令 l 在FreeMarker中,使用FTL标记引用指令 l 有三种FTL标记,这和HTML标记是类似的 开始标记 结束标记 空内容指令标记 l 有两种类型的指令预定义指令和用户定义指令 l 用户定义指令要使用替换,如...(会在后面讲述) l FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的 {being.name} for {being.price} Euros except for you l 如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息 flexpaper.studylead.coml FreeMarker会忽略FTL标记中的空白字符,如下面的例子 [BR] {being.name} for {being.price} Euros[BR] l 但是, \a at} l 注意Interpolation只能用于文本部分 l 通用Interpolation 插入字符串值直接输出表达式结果 插入数字值根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子 {answer} {answerstring} {answerstring.number} {answerstring.currency} {answerstring.percent} 输出结果是 42.00 42.00 42 flexpaper.studylead.com42.00 4,200 插入日期值根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子 {lastUpdatedstring“yyyy-MM-dd HHmmss zzzz“} {lastUpdatedstring“EEE, MMM d, yy“} {lastUpdatedstring“EEEE, MMMM dd, yyyy, hhmmss a zzz “} 输出的结果类似下面的格式 2003-04-08 212444 Pacific Daylight Time Tue, Apr 8, 03 Tuesday, April 08, 2003, 092444 PM PDT 插入布尔值根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子 {foostring“yes“, “no“} 输出结果是 yes l 数字Interpolation的{expr; at}形式可以用来格式化数字,at可以是 mX小数部分最小X位 MX小数部分最大X位 例子 {x; M2} {y; M2} {x; m1} {y; m1} {x; m1M2} {y; m1M2} FreeMarker设计指南4 flexpaper.studylead.com 4、杂项 (1)用户定义指令 l 宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏 l 基本用法 宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是一个例子 Hello Joe 作为用户定义指令使用宏变量时,使用替代FTL标记中的 如果没有体内容,也可以使用 l 参数 在macro指令中可以在宏变量之后定义参数,如 Hello {person} 可以这样使用这个宏变量 and 输出结果是 Hello Fred and Hello Batman 宏的参数是FTL表达式,所以下面的代码具有不同的意思 这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式 宏可以有多参数,下面是一个例子 Hello {person} flexpaper.studylead.com 可以这样使用该宏变量 其中参数的次序是无关的,因此下面是等价的 只能使用在macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是错误的 可以在定义参数时指定缺省值,如 Hello {person} 这样就正确了 宏的参数是局部变量,只能在宏定义中有效 l 嵌套内容 用户定义指令可以有嵌套内容,使用指令执行指令开始和结束标记之间的模板片断 例子 这样使用该宏变量 The bordered text 输出结果 The bordered text 指令可以被多次调用,例如 flexpaper.studylead.com Anything. 输出结果 Anything. Anything. Anything. 嵌套内容可以是有效的FTL,下面是一个有些复杂的例子 输出结果 Hello Joe Hello Joe Hello Joe 宏定义中的局部变量对嵌套内容是不可见的,例如 flexpaper.studylead.com {y} {count}/{x} {ydefault““} {xdefault““} {countdefault““} 输出结果 test 3/1 test 3/2 test 3/3 l 在宏定义中使用循环变量 用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在开始标记的参数后面指定循环变量的名字 例子 {c}. {halfc} Last 输出结果 1. 0.5 2. 1 3. 1.5 4. 2 Last 指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题 flexpaper.studylead.comn 调用时少指定循环变量,则多指定的值不可见 n 调用时多指定循环变量,多余的循环变量不会被创建 (2)在模板中定义变量 l 在模板中定义的变量有三种类型 plain变量可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换 局部变量在宏定义体中有效,使用local指令创建和替换 循环变量只能存在于指令的嵌套内容,由指令(如 list)自动创建;宏的参数是局部变量,而不是循环变量 l 局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子 1. {x} 6. {x} 7. {x} 8. {x} 9. {x} 2. {x} 3. {x} 4. {x} 5. {x} 输出结果 1. plain flexpaper.studylead.com 2. plain 3. local 4. loop 5. local 6. plain 7. loop 8. loop 9. plain2 l 内部循环变量隐藏同名的外部循环变量,如 {x} {x} {x} {x} {x} 输出结果 loop 1 loop 2 loop 3 loop 2 loop 1 l 模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe flexpaper.studylead.com{user} {.globals.user} (3)名字空间 l 通常情况,只使用一个名字空间,称为主名字空间 l 为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字空间,其目的是防止同名冲突 l 创建库 下面是一个创建库的例子(假设保存在lib/my_test.ftl中) Copyright C {date} Julia Smith. All rights reserved. Email {mail} 使用 import 指令导入库到模板中,Freemarker 会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量 {my.mail} {mail} 输出结果 Copyright C 1999-2002 Julia Smith. All rights reserved. Email jsmithacme.com jsmithacme.com fredacme.com 可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间 l 可以使用assign指令在导入的名字空间中创建或替代变量,下面是一个例子 {my.mail} {my.mail} l 输出结果 jsmithacme.com flexpaper.studylead.comjsmithother.com l 数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库 Copyright C {date} {user}. All rights reserved. l 假设数据模型中的user变量的值是Fred,则下面的代码 {my.mail} l 输出结果 Copyright C 1999-2002 Fred. All rights reserved. Fredacme.com Freemarker - 几个比较实用的例子 - - 用Freemarker做模本语言有一段时间了,列出几个和JSP或者Velocity相比起来比较方便的用途,目的是引诱更多的人跳上Freemarker这个贼船, 1. String内置的JavaScript转换 js_string 用途用于JavaScript转义,转换 ,“,换行等特殊字符 模板 alert“{errorMessagejs_string}“; flexpaper.studylead.com 输出 alert“Readonly\ s pet name is \“Cross Bone\““; 2.内置的默认值处理default 用途 用于处理默认值 模本 User {userLogin.namedefault“Anonymous“} {employee.department.manager.namedefault“ “} 输出 User Anonymous flexpaper.studylead.com 注,可以对整个对象树加上,再用内置处理器这种方便的做法,偶也是最近刚学会的,以前一直用很傻的方法做..... 3. Sequence内置的计数器 xxx_index 用途显示序号 模板 {e_index}. {e.name} 输出 1. Readonly 2. Robbin 4. Sequence内置的分段器 chunk flexpaper.studylead.com用途某些比较BT的排版需求 模板 {cell} {cell} 输出 a flexpaper.studylead.comb c d e f g h i j a b c d flexpaper.studylead.come f g h i j - - flexpaper.studylead.com