freemarker中文手册

更新时间:2024-01-12 15:13:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

开发笔记

截取字符

<#if news.title?length lt 13 > ${news.title}

<#else>

${news.title[0..12]}...

一、freemarker的空值和默认值

${user?if_exists}

${user?default('your name')}

判断对象是不是null <#if mouse?exists> Mouse found <#else>

或<#if book.name?? >

Mouse found

list 空值判断 <#if bookList?size = 0>

<#list recommendlist as content> <#if content_index%3==0>

<#if content_index%3==1> ${content.title}

<#if content_index%3==2> ${content.title}

<#list recommendlist as content> <#if content_index%3==0>

font-weight:bold; font-size:14px;

List指令还隐含了两个循环变量:

item_index:当前迭代项在所有迭代项中的位置,是数字值。

item_has_next:用于判断当前迭代项是否是所有迭代项中的最后一项。

在循环过程中,如果您想跳出循环,那么可以使用结合break指令,即<#break>来完成。 <#escape x as (x)!\ //去除null报错

三、 Freemarker如何遍历List实例应用

创通过上面的介绍,相信您已经对Freemarker如何遍历List有了了解,那么我们就废话少说,开始做一个应用吧。 User类

public class User{ private String username; private

(省略set和get方法) } user.ftl

<#--Freemarker遍历list--> 简单遍历list: <#list userList as user> 用户名:${user.userName} 密 码:${user.userPassword} 年 龄: ${user.age}

<#--Freemarker遍历list并应用list隐含变量item_index--> item_index使用: <#list userList as user> 第${user_index+1}个用户 用户名:${user.userName} 密 码:${user.userPassword}

年 龄: ${user.age}

<#--Freemarker遍历list并应用list隐含变量item_has_next--> item_has_next,size使用: <#list userList as user> 用户名:${user.userName} 密 码:${user.userPassword} 年 龄: ${user.age} <#if !user_has_next>

共有${userList?size}最后一个用户是:${user.userName}

<#--Freemarker遍历list并按用户年龄升序排序--> 按用户年龄升序排序:

<#list userList?sort_by(\ 用户名:${user.userName} 密 码:${user.userPassword} 年 龄: ${user.age}

<#--Freemarker遍历list并按用户年龄降序排序--> 按用户年龄降序排序:

<#list userList?sort_by(\ 用户名:${user.userName} 密 码:${user.userPassword} 年 龄: ${user.age}

<#--Freemarker遍历list当用户年龄大于21岁时,停止输出--> list中应用break:

<#list userList?sort_by(\ 用户名:${user.userName} 密 码:${user.userPassword} 年 龄: ${user.age} <#if (user.age>21) > <#break>

1、快速入门

(1)模板 + 数据模型 = 输出

? FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念

? 他们是分工劳动的:设计者专注于表示——创建HTML文件、图片、Web页面

的其它可视化方面;程序员创建系统,生成设计页面要显示的数据

? 经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的

? 在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码 ? 下面是一个例子:

Welcome!

Welcome ${user}!

Our latest product: ! ? 这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代

码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template) ? 至于user、latestProduct.url和latestProduct.name来自于数据模型(data model) ? 数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、

文件,甚至于在程序中直接生成

? 模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型 ? 下面是一个可能的数据模型:

(root) | +- user = \ | +- latestProduct | +- url = \ | +- name = \? 数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而user、url和name看作是文件,url和name文件位于latestProduct目录中(这只是一个比喻,实际并不存在) ? 当FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出:

Welcome!

Welcome Big Joe!

Our latest product: ! (2)数据模型 ? 典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子:

(root)

| +- animals | | | +- mouse | | | | | +- size = \ | | | | | +- price = 50 | | | +- elephant | | | | | +- size = \ | | | | | +- price = 5000 | | | +- python | | | +- size = \ | | | +- price = 4999 | +- test = \ | +- whatnot | +- because = \? 类似于目录的变量称为hashes,包含保存下级变量的唯一的查询名字 ? 类似于文件的变量称为scalars,保存单值

? scalars保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)

和数字(不要用引号将数字括起,这会作为字符串处理) ? 对scalars的访问从root开始,各部分用“.”分隔,如animals.mouse.price ? 另外一种变量是sequences,和hashes类似,只是不使用变量名字,而使用数字

索引,如下面的例子:

(root) | +- animals | | | +- (1st) | | | | | +- name = \ | | | | | +- size = \ | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = \ | | | | | +- size = \ | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = \ | | | +- size = \ | | | +- price = 4999 | +- whatnot | +- fruits | +- (1st) = \ | +- (2nd) = \? 这种对scalars的访问使用索引,如animals[0].name (3)模板

? 在FreeMarker模板中可以包括下面三种特定部分:

? ${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代 ? FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分,用#开始(有些以@开始,在后面叙述) ? 注释:包含在<#--和-->(而不是)之间 ? 下面是一些使用指令的例子:

? if指令

<#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#else> Pythons are not cheaper than elephants today. ? list指令

We have these animals: NamePrice <#list animals as being> ${being.name}${being.price} Euros 输出为:

We have these animals: NamePrice mouse50 Euros elephant5000 Euros python4999 Euros ? include指令 Test page

Test page

Blah blah... <#include \ ? 一起使用指令

We have these animals: NamePrice <#list animals as being> <#if being.size = \ ${being.name} <#if being.size = \ ${being.price} Euros FreeMarker设计指南(3) 3、模板

(1)整体结构

? 模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合:

? 文本:直接输出

? Interpolation:由${和},或#{和}来限定,计算值替代输出

? FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会

输出

? 注释:由<#--和-->限定,不会输出 ? 下面是以一个具体模板例子:

[BR] [BR] Welcome![BR] [BR] [BR] <#-- Greet the user with his/her name -->[BR]

Welcome ${user}!

[BR]

We have these animals:[BR] [BR] <#list animals as being>[BR] ${being.name} for ${being.price} Euros[BR] [BR] [BR] [BR]

? [BR]是用于换行的特殊字符序列 ? 注意事项:

? FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和

${NAME}是不同的

? Interpolation只能在文本中使用

? FTL标记不能位于另一个FTL标记内部,例如:

<#if <#include 'foo'>='bar'>... ? 注释可以位于FTL标记和Interpolation内部,如下面的例子:

Welcome ${user <#-- The name of user -->}!

[BR]

We have these animals:[BR] [BR] <#list <#-- some comment... --> animals as <#-- again... --> being>[BR] ... ? 多余的空白字符会在模板输出时移除 (2)指令

? 在FreeMarker中,使用FTL标记引用指令 ? 有三种FTL标记,这和HTML标记是类似的:

? 开始标记:<#directivename parameters>

? 结束标记:

? 空内容指令标记:<#directivename parameters/> ? 有两种类型的指令:

? FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的:预定义指令

和用户定义指令 ? 用户定义指令要使用@替换#,如<@mydirective>...(会在后面

讲述)

<#list animals as being> ${being.name} for ${being.price} Euros <#if use = \ (except for you) <#-- WRONG! --> ? 如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息 ? FreeMarker会忽略FTL标记中的空白字符,如下面的例子:

<#list[BR] animals as[BR] being[BR] >[BR] ${being.name} for ${being.price} Euros[BR] ? 但是,<、

? 直接指定值

? 字符串

? 使用单引号或双引号限定

? 如果包含特殊字符需要转义,如下面的例子:

${\\\\quoted\\\ and this is a backslash: \\\\\ ${'It\\'s \this is a backslash: \\\\'} 输出结果是: It's \quoted\ and this is a backslash: \\ It's \this is a backslash: \\ ? 下面是支持的转义序列: 转义序列 含义 \\\ \\' \\\\ \\n \\r \\t \\b \\f \\l \\g \\a \\{ \\xCode

双引号(u0022) 单引号(u0027) 反斜杠(u005C) 换行(u000A) Return (u000D) Tab (u0009) Backspace (u0008) Form feed (u000C) < > & {

4位16进制Unicode代码

? 有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\\和{等

不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:

${r\${r\输出的结果是: ${foo} C:\\foo\\bar ? 数字 ? 直接输入,不需要引号

? 精度数字使用“.”分隔,不能使用分组符号

? 目前版本不支持科学计数法,所以“1E3”是错误的 ? 不能省略小数点前面的0,所以“.5”是错误的 ? 数字8、+8、08和8.00都是相同的 ? 布尔值

? true和false,不使用引号 ? 序列

? 由逗号分隔的子变量列表,由方括号限定,下面是一个例子:

<#list [\ as x> ${x} 输出的结果是: winter spring summer autumn ? 列表的项目是表达式,所以可以有下面的例子: [2 + 2, [1, 2, 3, 4], \? 可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号 ? 可以定义反递增的数字范围,如5..2 ? 散列(hash)

? 由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下

面是一个例子:

{\? 键和值都是表达式,但是键必须是字符串 ? 获取变量

? 顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的

组合,且不能以数字开头 ? 从散列中获取数据

? 可以使用点语法或方括号语法,假设有下面的数据模型:

(root) | +- book | | | +- title = \ | | | +- author | | | +- name = \ | | | +- info = \ | +- test = \下面都是等价的: book.author.name book[\book.author.[\book[\? 使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果 ? 从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0

? 序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也

是序列);startIndex和endIndex是结果为数字的表达式 ? 特殊变量:FreeMarker内定义变量,使用.variablename语法访问

? 字符串操作

? Interpolation(或连接操作)

? 可以使用${..}(或#{..})在文本部分插入表达式的值,例如:

${\${\? 可以使用+操作符获得同样的结果 ${\${user + user + user + user} ? ${..}只能用于文本部分,下面的代码是错误的:

<#if ${isBig}>Wow! <#if \应该写成:

<#if isBig>Wow! ? 子串

? 例子(假设user的值为“Big Joe”):

${user[0]}${user[4]} ${user[1..4]} 结果是(注意第一个字符的索引是0):

BJ ig J ? 序列操作

? 连接操作:和字符串一样,使用+,下面是一个例子:

<#list [\- ${user} 输出结果是:

- Joe - Fred - Julia - Kate ? 散列操作 ? 连接操作:和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如:

<#assign ages = {\, \\, \- Joe is ${ages.Joe} - Fred is ${ages.Fred} - Julia is ${ages.Julia} 输出结果是:

- Joe is 30 - Fred is 25 - Julia is 18 ? 算术运算

? +、-、×、/、%,下面是一个例子:

${x * x - 100} ${x / 2} ${12 % 10} 输出结果是(假设x为5):

-75 2.5 2 ? 操作符两边必须是数字,因此下面的代码是错误的: ${3 * \? 使用+操作符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串,例如:

${3 + \输出结果是:

35 ? 使用内建的int(后面讲述)获得整数部分,例如:

${(x/2)?int} ${1.1?int} ${1.999?int} ${-1.1?int} ${-1.999?int} 输出结果是(假设x为5):

2 1 1 -1 -1 ? 比较操作符 ? 使用=(或==,完全相等)测试两个值是否相等,使用!= 测试两个值是否不相等 ? =和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = \会引起错误 ? Freemarker是精确比较,所以对\、\和\是不相等的 ? 对数字和日期可以使用<、<=、>和>=,但不能用于字符串

? 由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免

这种情况,例如<#if (x > y)>

? 另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>=

? 逻辑操作符

? &&(and)、||(or)、!(not),只能用于布尔值,否则会产生错误 ? 例子:

<#if x < 12 && color = \ We have less than 12 things, and they are green. <#if !hot> <#-- here hot must be a boolean --> It's not hot. ? 内建函数

? 内建函数的用法类似访问散列的子变量,只是使用“?”替代“.”,下面列出常用的一

些函数

? 字符串使用的:

? html:对字符串进行HTML编码 ? cap_first:使字符串第一个字母大写 ? lower_case:将字符串转换成小写 ? upper_case:将字符串转换成大写 ? trim:去掉字符串前后的空白字符 ? 序列使用的:

? size:获得序列中元素的数目 ? 数字使用的:

? int:取得数字的整数部分(如-1.9?int的结果是-1) ? 例子(假设test保存字符串\):

${test?html} ${test?upper_case?html} 输出结果是:

Tom & Jerry TOM & JERRY ? 操作符优先顺序

操作符组 操作符 后缀 一元 内建 乘法 加法 关系

[subvarName] [subStringRange] . (methodParams) +expr、-expr、! ?

*、 / 、% +、-

<、>、<=、>=(lt、lte、gt、gte)

相等 ==(=)、!=

逻辑and && 逻辑or

||

数字范围 ..

(4)Interpolation

? Interpolation有两种类型:

? 通用Interpolation:${expr}

? 数字Interpolation:#{expr}或#{expr; format} ? 注意:Interpolation只能用于文本部分 ? 通用Interpolation

? 插入字符串值:直接输出表达式结果

? 插入数字值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可

以使用内建函数string格式化单个Interpolation,下面是一个例子:

<#setting number_format=\<#assign answer=42/> ${answer} ${answer?string} <#-- the same as ${answer} --> ${answer?string.number} ${answer?string.currency} ${answer?string.percent} 输出结果是:

42.00 42.00 42 42.00 4,200% ? 插入日期值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子:

${lastUpdated?string(\${lastUpdated?string(\${lastUpdated?string(\ 输出的结果类似下面的格式:

2003-04-08 21:24:44 Pacific Daylight Time Tue, Apr 8, '03 Tuesday, April 08, 2003, 09:24:44 PM (PDT) ? 插入布尔值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子:

<#assign foo=true/> ${foo?string(\输出结果是:

yes ? 数字Interpolation的#{expr; format}形式可以用来格式化数字,format可以是: ? mX:小数部分最小X位 ? MX:小数部分最大X位 ? 例子:

<#-- If the language is US English the output is: --> <#assign x=2.582/> <#assign y=4/> #{x; M2} <#-- 2.58 --> #{y; M2} <#-- 4 --> #{x; m1} <#-- 2.6 --> #{y; m1} <#-- 4.0 --> #{x; m1M2} <#-- 2.58 --> #{y; m1M2} <#-- 4.0 --> FreeMarker设计指南(4)

4、杂项

(1)用户定义指令

? 宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用

macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏 ? 基本用法

? 宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是

一个例子:

<#macro greet> ? 作为用户定义指令使用宏变量时,使用@替代FTL标记中的#

<@greet> ? 如果没有体内容,也可以使用: <@greet/> ? 参数

? 在macro指令中可以在宏变量之后定义参数,如:

<#macro greet person> ? 可以这样使用这个宏变量: <@greet person=\/> and <@greet person=\/> 输出结果是:

and ? 宏的参数是FTL表达式,所以下面的代码具有不同的意思: <@greet person=Fred/> ? 这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式

? 宏可以有多参数,下面是一个例子:

<#macro greet person color> ? 可以这样使用该宏变量:

<@greet person=\

? 其中参数的次序是无关的,因此下面是等价的:

<@greet color=\? 只能使用在macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是错误的: <@greet person=\<@greet person=\? 可以在定义参数时指定缺省值,如:

<#macro greet person color=\> ? 这样<@greet person=\就正确了 ? 宏的参数是局部变量,只能在宏定义中有效 ? 嵌套内容

? 用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板

片断 ? 例子:

<#macro border> <#nested> 这样使用该宏变量:

<@border>The bordered text 输出结果:

The bordered text ? <#nested>指令可以被多次调用,例如:

<#macro do_thrice> <#nested> <#nested> <#nested> <@do_thrice> Anything. 输出结果:

Anything. Anything. Anything. ? 嵌套内容可以是有效的FTL,下面是一个有些复杂的例子:

<@border> <@do_thrice> <@greet person=\ 输出结果:

<#local y = \ <#list 1..count as x> ${y} ${count}/${x}: <#nested> <@repeat count=3>${y?default(\${count?default(\输出结果:

test 3/1: ? ? ? test 3/2: ? ? ? test 3/3: ? ? ? ?

? 在宏定义中使用循环变量

? 用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令

的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字 ? 例子:

<#macro repeat count> <#list 1..count as x> <#nested x, x/2, x==count> <@repeat count=4 ; c, halfc, last> ${c}. ${halfc}<#if last> Last! 输出结果:

1. 0.5 2. 1 3. 1.5 4. 2 Last! ? 指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题 ? 调用时少指定循环变量,则多指定的值不可见 ? 调用时多指定循环变量,多余的循环变量不会被创建

(2)在模板中定义变量

? 在模板中定义的变量有三种类型:

? plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换

? 局部变量:在宏定义体中有效,使用local指令创建和替换

? 循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的

参数是局部变量,而不是循环变量 ? 局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量

和plain变量,下面是一个例子:

<#assign x = \1. ${x} <#-- we see the plain var. here --> <@test/> 6. ${x} <#-- the value of plain var. was not changed --> <#list [\ 7. ${x} <#-- now the loop var. hides the plain var. --> <#assign x = \replace the plain var, hiding does not mater here --> 8. ${x} <#-- it still hides the plain var. --> 9. ${x} <#-- the new value of plain var. --> <#macro test> 2. ${x} <#-- we still see the plain var. here --> <#local x = \ 3. ${x} <#-- now the local var. hides it --> <#list [\ 4. ${x} <#-- now the loop var. hides the local var. --> 5. ${x} <#-- now we see the local var. again --> 输出结果:

1. plain 2. plain 3. local 4. loop 5. local 6. plain 7. loop 8. loop 9. plain2 ? 内部循环变量隐藏同名的外部循环变量,如: <#list [\ ${x} <#list [\ ${x} <#list [\ ${x} ${x} ${x} 输出结果:

loop 1 loop 2 loop 3 loop 2 loop 1 ? 模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:

<#assign user = \${user} <#-- prints: Joe Hider --> ${.globals.user} <#-- prints: Big Joe -->

(3)名字空间

? 通常情况,只使用一个名字空间,称为主名字空间

? 为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字

空间,其目的是防止同名冲突 ? 创建库

? 下面是一个创建库的例子(假设保存在lib/my_test.ftl中):

<#macro copyright date>

Copyright (C) ${date} Julia Smith. All rights reserved.
Email: ${mail}

<#assign mail = \? 使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量:

<#import \<#assign mail=\<@my.copyright date=\${my.mail} ${mail} 输出结果:

Copyright (C) 1999-2002 Julia Smith. All rights reserved.
Email: jsmith@acme.com

jsmith@acme.com fred@acme.com 可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间 ? 可以使用assign指令在导入的名字空间中创建或替代变量,下面是一个例子:

<#import \${my.mail} <#assign mail=\in my> ${my.mail} ? 输出结果: jsmith@acme.com jsmith@other.com ? 数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库: <#macro copyright date>

Copyright (C) ${date} ${user}. All rights reserved.

<#assign mail = %user}@acme.com\? 假设数据模型中的user变量的值是Fred,则下面的代码: <#import \<@my.copyright date=\${my.mail} ? 输出结果:

Copyright (C) 1999-2002 Fred. All rights reserved.

Fred@acme.com Freemarker - 几个比较实用的例子 - - 用Freemarker做模本语言有一

段时间了,列出几个和JSP或者Velocity相比起来比较方便的用途,目的是引诱更多的人跳上Freemarker这个贼船,

1. String内置的JavaScript转换: js_string

用途:用于JavaScript转义,转换',\换行等特殊字符 模板:

输出:

2.内置的默认值处理:default 用途: 用于处理默认值 模本:

User: ${userLogin.name?default(\

${(employee.department.manager.name)?default(\

输出:

User: Anonymous

注,可以对整个对象树加上(),再用内置处理器这种方便的做法,偶也是最近刚学会的,以前一直用很傻的方法做.....

3. Sequence内置的计数器: xxx_index 用途:显示序号 模板:

<#list employees as e> ${e_index}. ${e.name} 输出:

1. Readonly 2. Robbin

4. Sequence内置的分段器: chunk 用途:某些比较BT的排版需求 模板:

<#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']>

<#list seq?chunk(4) as row>

<#list row as cell>${cell}

<#list seq?chunk(4, '-') as row>

<#list row as cell>${cell}

输出: a b c d e f g h i j a

b c d e f g h i j - -

----------------------------------------------------------- FreeMarker是一个非常优秀的模板引擎,这个模板引擎可用于任何场景,FreeMarker负责将数据模型中的数据合并到模板中,从而生成标准输出.界面开发人员只需要关于界面(也就是模板文件)的开发,而业务逻辑开发者只需要负责将需要显示的数据填入数据模型

-----FreeMarker负责合并数据模型和模板,从而生成标准输出. FreeMarker特别适应于MVC模式的Web应用,虽然FreeMarker具有一些编程能力,但这种编程能力非常有限,无法实现业务逻辑,只能提供一些数据格式的转换功能.因此,通常由Java程序准备要显示的数据,由FreeMarker模板引擎来生成页面,而FreeMarker模板则提供页面布局支持.

此外,FreeMarker也是与Web容器无关的,也就是FreeMarker并不一定需要运行在Web容器中:FreeMarker同样可以应用于非Web应用程序环境.而且,FreeMarker并不是只能生成HTML页面,它也可以生成各种文本,如XML,RTF,Java源代码等.

Struts2默认采用FreeMarker作为其模板文件,而Struts2所有的主题模板文件都是采用FreeMarker编写的,eclipse中的JSP,Java等模板文件也是采用FreeMarker技术. 1,在java程序中使用FreeMarker

FreeMarker的模板就是一个.ftl文本文件,在该文件中使用了一些FreeMarker的特别标记,这些标记会动态显示,或者控制程序输出,如下面的模板文件代码: ${name},你好!${msg}

这里类似于${}的就是动态的内容,称作\插值\

为了使用FreeMarker来将数据模型中的值合并到模板文件中,可按如下步骤进行:

1,创建Configuration实例,该实例负责管理FreeMarker的模板加载路

径,负责生成模板实例

2,使用Configuration实例来生成Template实例,同进需要指定使用的模板文件

3,填充数据模型,数据模型就是一个Map对象 4,调用Template实例的process方法完成合并.

下面是一个使用FreeMarker创建输出的Java程序,程序源代码如下: package lee; import java.util.*; import java.io.*;

import freemarker.template.*; public class HelloFreeMarker {

private Configuration cfg; public void init() throws Exception {

//初始化FreeMarker配置 //创建一个Configuration实例 cfg = new Configuration(); //设置FreeMarker的模版文件位置

cfg.setDirectoryForTemplateLoading(new File(\ }

public void process()throws Exception {

Map root = new HashMap(); root.put(\

root.put(\您已经完成了第一个FreeMarker的示例\ Template t = cfg.getTemplate(\

t.process(root, new OutputStreamWriter(System.out)); }

public static void main(String[] args)throws Exception {

HelloFreeMarker hf = new HelloFreeMarker(); hf.init(); hf.process(); } }

上面的代码创建了一个Map实例,这个Map将作为模板文件的数据模型,我们要使用FreeMarker必须导入freemarker.jar文件,FreeMarker的官hen

tre

t.t

ps/

:o

/u

/rfc网reefeo

mr

ag

re

k.

,虽然FreeMarker可以在Java程序中使用,但大部分

时候还是用来生成HTML页面.

2,在Web应用中使用FreeMarker

在Web应用中使用FreeMarker跟在Java程序中使用并没有太大的区别.下面是是一个在Web中使用的例子,用来生成HTML页面的模板文件内容如下:

FreeMarker的HelloWorld ${message}

我们在Web应用中使用FreeMarker时,应该让Servlet来合并模板和数据,因此,Servlet负责创建Configuration实例,并负责合并模板和数据,下面是Servlet源代码: package lee; import java.util.*; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import freemarker.template.*;

public class HelloServlet extends HttpServlet

{

private Configuration cfg; public void init() {

//初始化FreeMarker配置 //创建一个Configuration实例 cfg = new Configuration(); //设置FreeMarker的模版文件位置

cfg.setServletContextForTemplateLoading(getServletContext(),

\ }

public void service(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//建立数据模型

Map root = new HashMap();

root.put(\ //取得模版文件

Template t = cfg.getTemplate(\ // 开始准备生成输出

// - 使用模版文件的charset作为本页面的charset // - 使用text/html MIME-type

response.setContentType(\ Writer out = response.getWriter();

//合并数据模型和模版,并将结果输出到out中 try {

t.process(root, out); }

catch (TemplateException e) {

throw new ServletException(\处理Template模版中出现错误\e); } } }

可以看到这个Servlet类的代码与普通的Java程序中使用FreeMarker大致一样,区别有两个:1,设置FreeMarker加载模板的方法不一样,在Servlet中设置加载的方法是setServletContextForTemplateLoading,第一个参数是本web应用的ServletContext,第二个参数是模板文件的路径.;2,结果必须输出到HttpServletResponse中,才能被浏览器加载.

配置Servlet的web.xml文件中的代码如下:

hello lee.HelloServlet

hello /hello

3,FreeMarker的模板文件

从上面的例子可以看到FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分

2,注释:<#-- ... -->格式部分,不会输出

3,插值:即${...}或#{...}格式的部分,将使用数据模型中的部分替代输出

4,FTL指令:FreeMarker指定,和HTML标记类似,名字前加#予以区分,不会输出

下面是一个FreeMarker模板的例子,包含了以上所说的4个部分


Welcome!


<#-- 注释部分 -->
<#-- 下面使用插值 -->

Welcome ${user} !


We have these animals:

<#-- 使用FTL指令 --> <#list animals as being>

${being.name} for ${being.price} Euros
<#list>


FreeMarker的语法知识将在下一篇文章中介绍

4,使用FreeMarker作为Struts2的视图技术

Struts2使用FreeMarker作为其默认的模板技术,因此Struts2对FreeMarker的支持非常良好,为了在Struts2中使用FreeMarker模板技术,只需要在struts.xml文件中进行简单配置即可.

4.1在FreeMarker模板中使用Struts2标签

在FreeMarker模板中使用标签毕竟不同于在JSP页面中使用标签,因为FreeMarker不支持使用taglib指令来导入标签库.但Struts2为了在FreeMarker模板中使用标签库提供了额外的支持.可以按照下面的步骤进行:

1,将系统所需要的标签库定义文件(.tld文件)复制到WEB-INF目录下,对于

Struts2,则是复制

struts2-core-2.0.11.2.jar

中的

META-INF\\struts-tags.tld文件

2,在web.xml文件中启动JspSupportServlet.为了启动它,则应该在web.xml文件中增加如下配置片段:

JspSupportServlet

org.apache.struts2.views.JspSupportServlet

1

3,在FreeMarker模板中使用assign指令导入标签库,导入标签库的代码如下:

<#-- 定义/WEB-INF/struts-tags.tld文件对应的标签库前缀为s --> <#assign s=JspTaglibs[\

4,在FreeMarker模板中增加了标签库的定义之后就可以使用了,下面是在FreeMarker模板中使用标签的代码: <#-- 在FreeMarker中使用Struts2标签 --> <@s.form action=\

<@s.textfield name=\用户名\<@s.textfield name=\密码\<@s.submit value=\提交\

如果是在JSP中使用Struts2标签,则格式如下:

值得注意的是,我们不能通过浏览器直接访问.ftl文件,否则将看到该模板页面的源代码,而不是我们想要的生成的HTML页面.这是因为Web容器默认不会处理FreeMarker模板页面.

在Struts2框架下,Struts2框架充当了之前的Servlet角色,只要浏览器的请求经过Struts2处理后,Struts2都会自动加载FreeMarker模板,并使用数据模型来填充该模板,再将最后的HTML页面输出给客户端.为了让所有的用户请求都经过Struts2的处理,这里将所有的FreeMarker模板放在WEB-INF\\ftl目录下.(WEB-INF目录下的所有文件客户端都是

不能直接访问的),因为浏览器无法访问.ftl文件了,因此我们在struts.xml配置文件中增加如下配置:

国为增加了上面的配置,在浏览器中请求login.action的时候,该action会被转向login.ftl模板.此时就可以看到返回的HTML页面. 4.2 使用FreeMarker的Result

从前面我们可以看到,使用FreeMarker与使用JSP作为输出文件并没有太大区别,下面来看看刚才的应用中Action中的代码: package lee;

import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; public class LoginAction implements Action {

private String username; private String password; public String getUsername() {

return username; }

public void setUsername(String username) {

this.username = username; }

public String getPassword() {

return password; }

public void setPassword(String password) {

this.password = password; }

public String execute() throws Exception {

if (getUsername().equals(\ && getPassword().equals(\ {

ActionContext.getContext().getSession().put(\getUsername());//这句很重要。 return SUCCESS; } else

,

{

return ERROR; } } }

此Action在struts.xml文件中的配置如下:

name=\

type=\

返回的成功页面代码如下:

成功页面

欢迎,${user},您已经登录!

可以看到这个成功页面会将user变量中的内容读出并显示,实际上,该

变量值将可以从多个地方取得,Struts2解析FreeMarker模板中变量的顺序如下:

1,FreeMarker模板内建的变量; 2,ValueStack中的变量; 3,ActionContext中的变量; 4,HttpServletRequest中的属性; 5,HttpSession中的属性; 6,ServletContext范围的属性.

FreeMarker模板的内建变量有如下几个:

1,stack:代表ValueStack本身,可通过如下方式来访问其中的变量\2,action:代表刚刚执行过的Action实例 3,response:代表HpptServletResponse实例 4,res:代表HpptServletResponse实例 5,request:代表HpptServletRequest实例 6,req:代表HpptServletRequest实例 7,session:代表HpptSession实例 8,application:代表ServletContext实例 9,base:代表用户请求的上下文路径. 4.3 FreeMarker中访问Servlet/JSP范围对象

Struts2还为在FreeMarker模板中访问Servlet/JSP范围对象提供了支持,通过这种支持可以直接访问这些变量.

访问application范围内的属性代码如下: <#if Application.attributeName?exists> ${Application.attributeName}

也可以通过使用Struts2标签来输出,代码如下: <@s.property value=\访问session范围内的属性如下: <#if Session.attributeName?exists> ${Session.attributeName}

<@s.property value=\访问request范围内的属性如下: <#if Request.attributeName?exists> ${Request.attributeName}

<@s.property value=\对于request,还可以访问request的请求参数,如下: <#if Parameter.parameterName?exists> ${Parameter.parameterName}

<@s.property value=\访问ValueStack上下文参数,代码如下: ${stack.findValue('#myContextParam')} 或

<@s.property value=\

struts2中使用freemarker

普通的struts2配置文件一般是这么配置的: /page.jsp

这里的view是一个jsp页面,也可以改成是一个freemarker模板页面: /fm.ftl

当然我们希望能在fm.ftl上使用struts2的标签,需要在fm.ftl页面最开始添加对struts2标签的引用:

<#assign s=JspTaglibs[\

引用前把struts2-core-2.0.x.x.jar包里的META-INF/struts-tags.tld 复制到 /WEB-INF/struts-tags.tld

默认是不支持JspTaglibs的引用的,这里还需要一个额外的配置,修

改web.xml,添加如下内容:

JspSupportServlet

org.apache.struts2.views.JspSupportServlet

1

一个简单的fm.ftl文件的例子:

<#assign s=JspTaglibs[\

http-equiv=“Content-Type“

content=“text/html;

charset=GB2312“> Insert title here

<@s.form action=“Action1.action“>

<@s.textfield name=“username“> <@s.textfield name=“password“> <@s.submit value=“提交“/>


登录用户名:${username}

注意:struts2在freemarker页面中标签写法和jsp页面的写法不同,freemarker里是<@s.form>,jsp里是,一定不要写错了! 使用时发现对中文的支持不好,显示时中文出现乱码,这里修改下struts.xml配置文件:

现在就可以在struts2中正常使用freemarker了! <#assign

security=JspTaglibs[\hs.g

pos

rr

ig

n/

gs

tfetrcpau:mr

i/et/

wwywo/rtwka.

\

<@security.authorize ifAnyGranted=\VE_RESOURCE\ /@security.authorize

Freemarker页面常用语法

A 概念

最常用的 3 个概念

本文来源:https://www.bwwdw.com/article/kcqo.html

Top