FreeMarker
学习内容: FreeMarker技术概述 FreeMarker基本语法FreeMarker开发问题总结
一、 FreeMarker技术概述
1.1 模板引擎技术
Freemarker 是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写,具有以下特点:
(1)Freemarker 适合被设计用来生成HTML Web页面,特别是基于MVC模式的应用程序。
(2)虽然Freemarker 具有一些编程的能力,但通常由Java程序准备要显示的数据,由Freemarker 生成页面,通过模板显示准备的数据 。
(3)Freemarker 不是一个Web应用框架,而适合作为Web应用框架一个组件。
(4)Freemarker 与容器无关,因为它并不知道HTTP或Servlet。
(5)Freemarker 更适合作为Model2框架(如Struts)的视图组件,你也可以在模板中使用JSP标记库。
(6)Freemarker 是免费的 。
数据模型+模版=输出
二、 FreeMarker基本语法
1、FreeMarker标记
FreeMarker标记的设计非常精炼,只有三种:
1) $ : ${expression} FreeMarker会在输出时用实际值进行替代
例如:${stockNum?default(‘’)}
2) # :标准的FTL标记。大部分FreeMarker指令都以#开始,可以 明显地与html标记区分,
<#if user = "BigJoe">our beloved leader</#if>。
同时,FTL文件的注释包含在<#--和-->(而不是<!--和-->)之间
3) @作为用户定义指令使用宏变量时,使用@替代FTL标记中的 #。后面将详细介绍宏
2标准的FTL标记指令
1) if, else, elseif
用例
<#if x = 1>
x is 1
</#if>
<#if x = 1>
x is 1
<#else>
x is not 1
</#if>
2) switch, case, default, break
<#--
list循环标记 数组或者集合 as 临时变量
临时变量_index 获取当前的索引从0开始
break标记 用于退出循环
-->
3) list, break 4) include 5) Import
include 和 import区别 :
总结:出现这种情况,在两个模版中都分别存在变量名都相同的变量的时候,include包含
进来,会进行覆盖,include只是将其公共的静态文件进行包含,而里面不涉及到内部函数以及变量
声明之类的,当涉及到这种问题,我们就要用import进行导入
语法:
<#import path as hash>
类似于java里的import,它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件
6) assign 7) macro, nested, return
问题小结:
FreeMarker是区分大小写的
FTL标记不能位于另一个FTL标记内部,例如:<#if <#include 'foo'>='bar'>...</if>
${…}只能在文本中使用
多余的空白字符会在模板输出时去除
如果使用的指令不存在,会产生一个错误消
3: FTL内置的处理函数【类似于 fn函数】
用法类似访问对象的子变量,只是使用"?"替代".",例如:${user?upper_case}
【对于字符串】
html-对字符串进行HTML编码
cap_first-使字符串第一个字母大写
lower_case-将字符串转换成小写
trim-去掉字符串前后的空白字符
length –取得字符串长度
js_string---包含的特殊字符(如回车、\”),转化成变量可以接收的值
例:
<#assign beanName = 'The "foo" bean.'>
var BEAN_NAME = "${beanName?j_string}";
结果:String BEAN_NAME = "The \"foo\" bean.";
【对于Sequences】
size-获得序列中元素的数目
【对于数字】
int-取得数字的整数部分(如-1.9?int的结果是-1 )
例子:
<#-- FTL内置的处理函数 类似于 fn函数-->
<#assign str='hello my name is jiaozi'>
${str?length}
${str?trim}
${str?upper_case}
${userList?size}
<#if aa?exists>
#{aa}
</#if>
4. <#--宏的用法 -->
<#macro mymacro p1 p2>
我的结果:${p1+p2}
</#macro>
<@mymacro p1=10 p2=128 />
<@mymacro p1=23 p2=128 />
5. 其他处理:
<#--Map的循环这样子玩-->
<#list myId?values as tmp>
${tmp}
</#list>
<#--freeMarker数组玩法-->
<#assign arr=['a','b'] >
<#list arr as tmp>
${tmp}
</#list>
6.<#--总结:面试题-->
<#include "include2.ftl">
<#include "include.ftl">
${age}
<#import "include2.ftl" as c>
<#import "include.ftl" as c1>
${c.age} -- ${c1.age}
-----------------------------------------------------
三、 FreeMarker开发问题总结
1:特殊字符的显示
如果包含特殊字符需要转义,如下面的例子
${"It's \"quoted\" and this is a backslash: \\"}
${'It\'s "quoted" and this is a backslash: \\'}
输出结果
It's "quoted" and this is a backslash: \
It's "quoted" and this is a backslash: \
有一类特殊的字符串称为raw字符串,被认为是纯文本:
${r"${foo}"}
${r"C:\foo\bar"}
${foo}
C:\foo\bar
2:使用过程当中容易出错的地方
下面的代码是错误的
<#if ${isBig}>Wow!</#if>
<#if "${isBig}">Wow!</#if>
应该写成下面这样
<#if isBig>Wow!</#if>
FreeMarker对null值有严格的校验,它将其视为missing
variable,报错!。为了防止错误发生我们可以为其设置当表
达式为null时的默认值:stockNum?default('')
&&(and)、||(or)、!(not),只能用于布尔值,否则
会产生错误
问题小结:
FreeMarker是区分大小写的
FTL标记不能位于另一个FTL标记内部,例如:<#if <#include 'foo'>='bar'>...</if>
${…}只能在文本中使用
多余的空白字符会在模板输出时去除
如果使用的指令不存在,会产生一个错误消
3:FTL内置的处理函数
用法类似访问对象的子变量,只是使用"?"替代".",例如:${user?upper_case}
【对于字符串】
html-对字符串进行HTML编码
cap_first-使字符串第一个字母大写
lower_case-将字符串转换成小写
trim-去掉字符串前后的空白字符
length –取得字符串长度
js_string---包含的特殊字符(如回车、\”),转化成变量可以接收的值
例:
<#assign beanName = 'The "foo" bean.'>
var BEAN_NAME = "${beanName?j_string}";
结果:String BEAN_NAME = "The \"foo\" bean.";
【对于Sequences】
size-获得序列中元素的数目
【对于数字】
int-取得数字的整数部分(如-1.9?int的结果是-1 )
【其它处理】
xml---xml安全处理
if_exists、exists:
判断对象是不是null列:
<#if mouse?exists>
Mouse found
<#else>
也可以直接${mouse?if_exists})输出布尔形
keys---返回hash里的所有keys, 返回结果类型sequence
values---返回hash里的所有value, 返回结果类型sequence
string---string(‘#’)、 string(‘是’,’否’)、 string(‘#.00’)、 string(‘yyyy-MM-dd hh:mm:ss’)、 string(‘#.##’)、 string(‘0.##’)、
string.currency:指定数值以¥42.00 显示
4: sequence 序列(对应java里的list、数组等非键值对的集合) 与hash键值对的集合
主要是针对 hash结构怎样展示
<#list yourMap?keys as key>
${key} = ${ yourMap [key]};
</#list>
Xx代表集合,判定集合是否为空
<#if (xx.empty)>
</#if>
Set xx = new HashSet(); 对于Set这种集合以上的判定 FTL会
报错,应该转化之后
ArrayList xx = new ArrayList(new HashSet()) 再存入 数据模型当中
5:模板中的变量的使用范围及命名空间
变更的使用范围:
plain(全局)变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换
局部变量:在macro中有效,使用local指令创建和替换
循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量
局部变量隐藏(而不是覆盖)同名的plain变量;
循环变量隐藏同名的局部变量和plain变量,下
面是一个例子 :
<#assign x = "plain">
1. ${x}
<@test/>
6. ${x}
<#list ["loop"] as x>
7. ${x}
<#assign x = "plain2">
8. ${x}
</#list>
9. ${x}
<#macro test>
2. ${x}
<#local x = "local">
3. ${x}
<#list ["loop"] as x>
4. ${x}
</#list>
5. ${x}
</#macro>
6:模板中的变量会隐藏(而不是覆盖)数据模型中同名变
量,如果需要访问数据模型中的同名变量,使用特殊变
量global,下面的例子假设数据模型中的user的值是
Big Joe:
<#assign user = "Joe Hider">
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->
命名空间技术:
通常情况,只使用一个命名空间,称为主命名空间
(main namespace),但你是不会意识到这些的;为了
创建可重用的macro必须使用多命名空间,为了防止同
名冲突,列如:
首先创建一个库(假设保存在lib/my_test.ftl中):
<#macro copyright date>
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "jsmith@acme.com">
使用import指令导入库到模板中,Freemarker会为导入的库创建新
的命名空间,并可以通过import指令中指定的hash(散列)变量访问库
中的变量:
<#import "/lib/my_test.ftl" as my>
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
小结:上面的例子中使用的两个同名变量并没有冲突,因为它
们位于不同的命名空间,可以使用assign指令在导入的命
名空间中创建或替代变量:
<#import "/lib/my_test.ftl" as my>
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}
数据模型中的变量任何地方都可见,也包括不同的命名空间。