Freemarker常用技巧(二)

摘要:
本文主要介绍FreeMarker的缓存实现。处理模板时,FreeMarker直接从缓存中返回相应的模板对象,并具有默认机制以确保模板对象与模板文件同步。FreeMarker定义了统一的缓存处理接口CacheStorage。默认实现是最近最少使用的MruCacheStorage缓存策略。默认情况下,这两个值FreeMarker为0,Integer MAX_VALUE表示模板缓存的数量不受限制。必须分配Freemarker空值处理Freemarker变量,否则将引发异常。FreeMarker提供了两个运算符来避免空值:!Freemarker数据类型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 最近最少使用的缓存策略。一般情况下,很少需要对缓存进行扩展处理。您可以通过下面的代码指定最大缓存的模版数:

 
1
cfg.setCacheStorage(newfreemarker.cache.MruCacheStorage(20,250))

其中第一个参数是最大的强引用对象数,第二个为最大的弱引用对象数。这两个值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: awstring"
数字类型
输入不带引号的数字就可以直接指定一个数字,必须使用点作为小数的分隔符而不能是其他的分组分隔符。可以使用-或+来表明符号(+是多余的)。科学记数法暂不支持使用(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常用技巧(二)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇oracle的sqlnet.ora,tnsnames.ora,listener.ora三个配置文件Python 2.75升级3.6.3下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

深入探讨this指针

深入探讨this指针   为了写这篇文章,准备了好长时间,翻遍了箱底的书籍。可是如今还是不敢放开手来写,战战兢兢。不是操心自己写错,而是唯恐自己错误误导别人。同一时候也希望这篇文章能给你一点收获。既然是深入探讨this指针,所以建议刚開始学习的人,最好具有一定编译基础,调试基础。假设大家觉得这片文章有不满的地方,就给我发信批评一下,以便及时修正。 关于t...

AndroidStudio自定义TODO

1.增加自定义TODO标记 Preferences -> Editor -> TODO,然后点击左下角的加号,输入想要自定义的TODO的正则 输入X.*(X为TODO标签的名字),这里以to_complete为例,输入to_complete.* 把defaultcolor的勾选去掉,可以自定义直观的配色: 两步你就可以手动输入并使用自定义...

Oracle常用函数汇总

在Oracle OCP考试中,相当一部分知识点涉及到对于Oracle常见函数的考查。尽管Oracle官方文档SQL Language Reference中Functions一章内列举了所有Oracle自带函数,但如果要系统的看一遍,还是要花费相当的精力,更何况还是英文呢。如果碰到一个不熟悉的,就查一下,不经常用,又很容易遗忘。下面就对Oracle常见函数做...

数组概述和特点

数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:       1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。       2. 其元素必须是相同类型,不允许出现混合类型。       3. 数组类型可...

JS常用知识点(一)

1.js数据类型   基本类型:String、Number、boolean、null、undefined、Symbol   引用类型:Object   null和undefined的区别:undefined表示定义但未赋值。null表示定义并赋值,但值为null,可用于对象的初始化或销毁。   Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属...

Mac下的IDEA快捷键

  快捷键 功能 Option + enter 打开提示 Command + / 注释方式是“行注释”;可以注释当前行、取消当前行的注释 注释选中的内容、取消选中行的注释 Option + Command + / 注释方式为“多行注释”;注释选中的内容、取消注释 Option + Command + L 格式化代码 Comman...