Freemarker常用技巧(二)

1 list、break指令
<#list sequence as item>
  ...
</#list>
tem_index:当前变量的索引值.
item_has_next:是否存在下一个对象.
<#list ["星期一","星期二","星期三","星期四","星期五","星期六"] as x>
${x_index + 1}.${x}
<#if x_has_next>,</#if>
<#if x="星期四"><#break></#if>
</#list>
输出结果:
1.星期一,
2.星期二,
3.星期三,
4.兴趣四,


2 import指令
<#import path as mapObject>
path:指定要被导入的模板文件.
mapObject:是一个Map对象.
意思:将path路径中的变量都放在mapObject中.
例子:<#import "/lib/common.ftl" as com>


3 宏的基本用法
例如:
<#macro greet>
<font size="+2"> Hello JOE!</font>
</#macro>
使用时:
<@greet></@greet>
如果没有体内容也可以用
<@greet />
可以在宏定义之后定义参数,宏参数是局部变量,只在宏定义中有效。如:
<#macro greet person>
<font size="+2"> Hello ${person}!</font>
</#macro>
使用时:
<@greet person="emma"> and <@greet person="LEO">
输出为:
<font size="+2"> Hello emma!</font>
<font size="+2"> Hello LEO!</font>
注意:宏的参数是FTL表达式,所以,person=emma和上面的例子中具有不同的意义,这意味着将变量emma的值传给person,这个值可能是任意一种数据类型,甚至是一个复杂的表达式。
宏可以有多个参数,使用时参数的次序是无关的,但是只能使用宏中定义的参数,并且对所有参数赋值。如:
<#macro greet person color>
<font size="+2" color="${color}"> Hello ${person}!</font>
</#macro>
使用时:
<@greet color="black" person="emma" />正确
<@greet person="emma" />错误,color没有赋值,此时,如果在定义宏时为color定义缺省值<#macro greet person color="black">这样的话,这个使用方法就是正确的。

 

FreeMarker缓存处理

上周我面试了一个人,无意中我问了一个问题:freemarker加载模板文件的缓存策略是什么呢?很遗憾,面试者没有回答出来。后来,我告诉面试者,学习一个框架,不仅仅是要明白这个框架如何使用,还要了解一下框架的底层实现。本文主要是给大家说一下FreeMarker的缓存实现部分。本文的内容大部分来自于互联网,要想更深入的了解与掌握
FreeMarker缓存处理,我个人觉得还是要深入研读源码,然后再看看网上的分析以加深印象,这样的学习效果是最好的。
FreeMarker 的缓存处理主要用于模版文件的缓存,一般来讲,模版文件改动不会很频繁,在一个流量非常大的网站中,如果频繁的读取模版文件对系统的负担还是很重的,因此 FreeMarker 通过将模版文件的内容进行缓存,来降低模版文件读取的频次,降低系统的负载。
当处理某个模版时,FreeMarker直接从缓存中返回对应的 Template 对象,并有一个默认的机制来保证该模版对象是跟模版文件同步的。如果使用的时候 FreemarkerServlet 时,有一个配置项template_update_delay用来指定更新模版文件的间隔时间,相当于多长时间检测一下是否有必要重新加载模版文件,0 表示每次都重新加载,否则为多少毫秒钟检测一下模版是否更改。
FreeMarker定义了一个统一的缓存处理接口CacheStorage,默认的实现是 MruCacheStorage 最近最少使用的缓存策略。一般情况下,很少需要对缓存进行扩展处理。您可以通过下面的代码指定最大缓存的模版数:

其中第一个参数是最大的强引用对象数,第二个为最大的弱引用对象数。这两个值FreeMarker默认的是0和 Integer.MAX_VALUE,表明模版缓存数是无限的。

 

freemarker空值的处理

FreeMarker的变量必须赋值,否则就会抛出异常。而对于FreeMarker来说,null值和不存在的变量是完全一样的,因为FreeMarker无法理解null值。FreeMarker提供两个运算符来避免空值:
(1)!运算符:指定缺失变量的默认值;
(2)??运算符:判断变量是否存在。
!运算符有两种用法:variable!或variable!defaultValue。第一种用法不给变量指定默认值,表明默认值是空字符串、长度为0的集合、或长度为0的Map对象。
注意:使用!运算符指定默认值并不要求默认值的类型和变量类型相同。下面是一个小例子:
<#-- ${sss}没有定义这个变量,会报异常!-->
${sss!} <#--没有定义这个变量,默认值是空字符串!-->
${sss!"abc"} <#--没有定义这个变量,默认值是字符串abc!-->
??运算符返回布尔值,如:variable??,如果变量存在,返回true,否则返回false。一般情况下与if指令共同使用。将它和if指令合并,如下面的例子:如果user变量不存在的话将会忽略整个问候代码段:
<#if user??><h1>Welcome ${user}!</h1></#if>
关于多级访问的变量,比如animals.python.price,书写代码:animals.python.price!0,仅当animals.python存在而仅仅最后一个子变量price可能不存在(这种情况下我们假设价格是0)。如果animals或者python不存在,那么模板处理过程将会以“未定义的变量”错误而停止。为了防止这种情况的发生,可以这样来书写代码(animals.python.price)!0。这种情况下当animals或python不存在时表达式的结果仍然是0。对于??也是同样用来的处理这种逻辑的:animals.python.price??对比(animals.python.price)??来看。

 

freemarker数据类型

freemarker的数据类型主要包括下面几类:
字符串类型
定义字符串可以使用双引号和单引号,例如:
<#assign temp = "some text"  />
或者
<#assign temp = 'some text'  />
这两种形式是相等的。字符串中可以使用转义字符"\"。如果字符串内有大量的特殊字符,则可以在引号的前面加上一个字母r,则字符串内的所有字符都将直接输出。例如:"It's \"quoted\"" 或者 r"C:\raw\string"
数字类型
输入不带引号的数字就可以直接指定一个数字,必须使用点作为小数的分隔符而不能是其他的分组分隔符。可以使用-或+来表明符号(+是多余的)。科学记数法暂不支持使用(1E3就是错误的),而且也不能在小数点之前不写0(.5也是错误的)。
哈希表类型
键和值成对出现并以冒号分隔,最外面使用花括号。看这个例子:
<#assign temp = {"name":"green mouse", "price":150} />
注意到名字和值都是表达式,但是用来检索的名字就必须是字符串类型的。
序列类型
指定一个序列,使用逗号来分隔其中的每个子变量,然后把整个列表放到方括号中。例如:
<#assign nums=[1,2,3,4,5,77,8,99]/>
使用list指令将序列输出,如下所示:
<#list nums as num>
   ${num}
</#list>
还可以采用数字范围定义了一个连续的序列,例如:
<#assign nums=12..99/>
这种方式定义的序列的内容是12到99。总之,使用数字范围也可以表示一个数字集合,如1..5等同于集合[1,2, 3, 4, 5];同样也可以用5..1来表示[5, 4, 3, 2, 1]。
时间类型
FreeMarker支持date、time、datetime三种类型,这三种类型的值无法直接指定,通常需要借助字符串的date、time、datetime三个内建函数进行转换才可以:
 <#assign test1 = "2009-01-22"?date("yyyy-MM-dd") />;
 <#assign test2 ="16:34:43"?time("HH:mm:ss") />
 <#assign test2 = "2009-01-22 17:23:45"?datetime("yyyy-MM-dd HH:mm:ss") />
布尔类型
直接使用true或false,不使用引号。例如:<#assign temp = true />

 

freemarker的配置简介

在freemarker启动的过程中,参与配置功能的类主要有四个:Configurable,Configuration,Template和Environment。下面给大家简单介绍一下这里类的特点,内容主要是出自freemarker的源码,而且这些英文比较简单,稍微耐心一点就可以读懂的。

Configurable简介

This is a common superclass of {@link freemarker.template.Configuration},{@link freemarker.template.Template}, and {@link Environment} classes.
It provides settings that are common to each of them. FreeMarker uses a three-level setting hierarchy - the return value of every setting getter method on <code>Configurable</code> objects inherits its value from its parent <code>Configurable</code> object, unless explicitly overridden by a call to a corresponding setter method on the object itself. The parent of an 
<code>Environment</code> object is a <code>Template</code> object, the parent of a <code>Template</code> object is a <code>Configuration</code> object.

Configuration简介

The main entry point into the FreeMarker API; encapsulates the configuration settings of FreeMarker, also serves as a central template-loading and caching service.
This class is meant to be used in a singleton pattern. That is, you create an instance of this at the beginning of the application life-cycle, set its {@link #setSetting(String, String) configuration settings} there (either with the setter methods like {@link #setTemplateLoader(TemplateLoader)} or by loading a {@code .properties} file), and then use that single instance everywhere in your application. Frequently re-creating {@link Configuration} is a typical and grave mistake from performance standpoint, as the {@link Configuration} holds the template cache, and often also the class introspection cache, which then will be lost. (Note that, naturally,having multiple long-lived instances,like one per component that internally uses FreeMarker is fine.)  
The basic usage pattern is like:
// Where the application is initialized; in general you do this ONLY ONCE in the application life-cycle!
Configuration cfg = new Configuration(VERSION_X_Y_Z));
// Where X, Y, Z enables the not-100%-backward-compatible fixes introduced in
// FreeMarker version X.Y.Z  and earlier (see {@link #Configuration(Version)}).
cfg.setSomeSetting(...);
cfg.setOtherSetting(...);

Template简介

Stores an already parsed template, ready to be processed (rendered) for unlimited times, possibly from multiple threads.
Typically, you will use {@link Configuration#getTemplate(String)} to create/get {@link Template} objects, so you don't construct them directly. But you can also construct a template from a {@link Reader} or a {@link String} that contains the template source code. But then it's important to know that while the resulting {@link Template} is efficient for later processing, creating a new {@link Template} itself is relatively expensive. So try to re-use {@link Template} objects if possible.{@link Configuration#getTemplate(String)} does that (caching {@link Template}-s) for you, but the constructor of course doesn't, so it's up to you to solve then.
Objects of this class meant to be handled as immutable and thus thread-safe. However, it has some setter methods for changing FreeMarker settings. Those must not be used while the template is being processed, or if the template object is already accessible from multiple threads.

Environment简介

Object that represents the runtime environment during template processing. For every invocation of a <tt>Template.process()</tt> method, a new instance
of this object is created, and then discarded when <tt>process()</tt> returns.
This object stores the set of temporary variables created by the template,the value of settings set by the template, the reference to the data model root,etc. Everything that is needed to fulfill the template processing job.
Data models that need to access the Environment object that represents the template processing on the current thread can use the {@link #getCurrentEnvironment()} method.
If you need to modify or read this object before or after the process call, use {@link Template#createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)}

你可能感兴趣的:(Freemarker常用技巧(二))