﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-java 友人帮-文章分类-FreeMarker </title><link>http://www.blogjava.net/jzone/category/40488.html</link><description>java web, java wap ..My laboratory..</description><language>zh-cn</language><lastBuildDate>Tue, 27 Apr 2010 06:23:32 GMT</lastBuildDate><pubDate>Tue, 27 Apr 2010 06:23:32 GMT</pubDate><ttl>60</ttl><item><title>FreeMarker 字符串的截取</title><link>http://www.blogjava.net/jzone/articles/318932.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Wed, 21 Apr 2010 01:53:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/318932.html</guid><description><![CDATA[取字符串长度：${str?length}<br />
截取字符串方法一：${str[0..5]}<br />
截取字符串方法二：${str?substring(0,5)}
<img src ="http://www.blogjava.net/jzone/aggbug/318932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2010-04-21 09:53 <a href="http://www.blogjava.net/jzone/articles/318932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>巧用Freemarker的自定义方法</title><link>http://www.blogjava.net/jzone/articles/314371.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Wed, 03 Mar 2010 01:53:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/314371.html</guid><description><![CDATA[原文：<a href="http://gzhzh.javaeye.com/blog/433273">http://gzhzh.javaeye.com/blog/433273</a> <br />
<br />
一直以来，都想在FTL模板页面里应用java的方法。<br />
&#8220;要想使用Freemarker支持的自定义方法，需要实现freemarker.template.TemplateMethodModel接口，然后将方法对象放入到Freemarker的数据模型中，这样在ftl文件中便可以像使用Freemarker内置方法一样使用该方法了。&#8221;<br />
<br />
具体的需求方法：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">package</span><span style="color: #000000">&nbsp;yixun.wap.tools;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.List;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;freemarker.template.TemplateMethodModel;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;freemarker.template.TemplateModelException;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_209_603_Open_Image" onclick="this.style.display='none'; Codehighlighter1_209_603_Open_Text.style.display='none'; Codehighlighter1_209_603_Closed_Image.style.display='inline'; Codehighlighter1_209_603_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_209_603_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_209_603_Closed_Text.style.display='none'; Codehighlighter1_209_603_Open_Image.style.display='inline'; Codehighlighter1_209_603_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;EncodeURLMethod&nbsp;</span><span style="color: #0000ff">implements</span><span style="color: #000000">&nbsp;TemplateMethodModel&nbsp;</span><span id="Codehighlighter1_209_603_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_209_603_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img id="Codehighlighter1_213_340_Open_Image" onclick="this.style.display='none'; Codehighlighter1_213_340_Open_Text.style.display='none'; Codehighlighter1_213_340_Closed_Image.style.display='inline'; Codehighlighter1_213_340_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_213_340_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_213_340_Closed_Text.style.display='none'; Codehighlighter1_213_340_Open_Image.style.display='inline'; Codehighlighter1_213_340_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_213_340_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff">/**&nbsp;*/</span><span id="Codehighlighter1_213_340_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;执行方法&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@param</span><span style="color: #008000">&nbsp;argList&nbsp;方法参数列表&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@return</span><span style="color: #008000">&nbsp;Object&nbsp;方法返回值&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080">@throws</span><span style="color: #008000">&nbsp;TemplateModelException&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br />
<img id="Codehighlighter1_403_601_Open_Image" onclick="this.style.display='none'; Codehighlighter1_403_601_Open_Text.style.display='none'; Codehighlighter1_403_601_Closed_Image.style.display='inline'; Codehighlighter1_403_601_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_403_601_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_403_601_Closed_Text.style.display='none'; Codehighlighter1_403_601_Open_Image.style.display='inline'; Codehighlighter1_403_601_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Object&nbsp;exec(List&nbsp;arg0)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;TemplateModelException&nbsp;</span><span id="Codehighlighter1_403_601_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_403_601_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_428_510_Open_Image" onclick="this.style.display='none'; Codehighlighter1_428_510_Open_Text.style.display='none'; Codehighlighter1_428_510_Closed_Image.style.display='inline'; Codehighlighter1_428_510_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_428_510_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_428_510_Closed_Text.style.display='none'; Codehighlighter1_428_510_Open_Image.style.display='inline'; Codehighlighter1_428_510_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(arg0.size()&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_428_510_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_428_510_Open_Text"><span style="color: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">限定方法中必须且只能传递一个参数</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throw</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;TemplateModelException(</span><span style="color: #000000">"</span><span style="color: #000000">template&nbsp;exception</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;encode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;java.net.URLEncoder.encode((String)&nbsp;arg0.get(</span><span style="color: #000000">0</span><span style="color: #000000">));<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;encode;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
<br />
将EncodeURLMethod的实例对象放入模型中输出：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">body.put(</span><span style="color: #000000">"</span><span style="color: #000000">encodeURL</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;EncodeURLMethod());</span></div>
<br />
在Freemarker模版文件中应用：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_1_23_Open_Image" onclick="this.style.display='none'; Codehighlighter1_1_23_Open_Text.style.display='none'; Codehighlighter1_1_23_Closed_Image.style.display='inline'; Codehighlighter1_1_23_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_1_23_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_1_23_Closed_Text.style.display='none'; Codehighlighter1_1_23_Open_Image.style.display='inline'; Codehighlighter1_1_23_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /><span style="color: #000000">$</span><span id="Codehighlighter1_1_23_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_1_23_Open_Text"><span style="color: #000000">{body.encodeURL(</span><span style="color: #000000">"</span><span style="color: #000000">时时彩</span><span style="color: #000000">"</span><span style="color: #000000">)}</span></span></div>
<br />
得到的就是经过encoder的数据串了。这样用起来就非常方便了，可以根据业务的需求，扩大FreeMarker的内置方法库。
<img src ="http://www.blogjava.net/jzone/aggbug/314371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2010-03-03 09:53 <a href="http://www.blogjava.net/jzone/articles/314371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FreeMarke开发指南</title><link>http://www.blogjava.net/jzone/articles/291812.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Wed, 19 Aug 2009 10:16:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/291812.html</guid><description><![CDATA[<p>1概念<br />
2指令<br />
if, else, elseif <br />
switch, case, default, break<br />
list, break <br />
include <br />
Import <br />
compress <br />
escape, noescape <br />
assign <br />
global <br />
setting <br />
macro, nested, return<br />
t, lt, rt <br />
3一些常用方法或注意事项 <br />
表达式转换类 <br />
数字循环 <br />
对浮点取整数 <br />
给变量默认值 <br />
判断对象是不是null <br />
常用格式化日期 <br />
添加全局共享变量数据模型 <br />
直接调用java对象的方法 <br />
字符串处理(内置方法) <br />
在模板里对sequences和hashes初始化 <br />
注释标志 <br />
sequences内置方法 <br />
hashes内置方法 <br />
4 freemarker在web开发中注意事项 <br />
web中常用的几个对象 <br />
view中值的搜索顺序 <br />
在模板里ftl里使用标签 <br />
如何初始化共享变量 <br />
与webwork整合配置 <br />
5高级方法 <br />
自定义方法 <br />
自定义 Transforms <br />
<br />
</p>
<p>1概念<br />
最常用的3个概念<br />
sequence&nbsp; 序列，对应java里的list、数组等非键值对的集合<br />
hash&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 键值对的集合<br />
namespace 对一个ftl文件的引用,利用这个名字可以访问到该ftl文件的资源</p>
<p>2指令<br />
<span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">if, else, elseif</strong></span><br />
语法<br />
&lt;#if condition&gt;<br />
&nbsp; ...<br />
&lt;#elseif condition2&gt;<br />
&nbsp; ...<br />
&lt;#elseif condition3&gt;<br />
&nbsp; ...<br />
&lt;#else&gt;<br />
&nbsp; ...<br />
&lt;/#if&gt;<br />
<br />
<span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">switch, case, default, break</strong></span><br />
语法<br />
&lt;#switch value&gt;<br />
&nbsp; &lt;#case refValue1&gt;<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; &lt;#case refValue2&gt;<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; ...<br />
&nbsp; &lt;#case refValueN&gt;<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; &lt;#default&gt;<br />
&nbsp;&nbsp;&nbsp; ...<br />
&lt;/#switch&gt;</p>
<p>用例<br />
字符串<br />
&lt;#switch being.size&gt;<br />
&nbsp; &lt;#case "small"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; This will be processed if it is small<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; &lt;#case "medium"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; This will be processed if it is medium<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; &lt;#case "large"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; This will be processed if it is large<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;#break&gt;<br />
&nbsp; &lt;#default&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; This will be processed if it is neither<br />
&lt;/#switch&gt;<br />
数字<br />
&lt;#switch x&gt;<br />
&nbsp; &lt;#case x = 1&gt;<br />
&nbsp;&nbsp;&nbsp; 1<br />
&nbsp; &lt;#case x = 2&gt;<br />
&nbsp;&nbsp;&nbsp; 2<br />
&nbsp; &lt;#default&gt;<br />
&nbsp;&nbsp;&nbsp; d<br />
&lt;/#switch&gt;</p>
<p>如果x=1 输出 1 2, x=2输出 2, x=3 输出d</p>
<p><span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">list, break</strong></span><br />
语法<br />
&lt;#list sequence as item&gt;<br />
...<br />
&lt;#if item = "spring"&gt;&lt;#break&gt;&lt;/#if&gt;<br />
...<br />
&lt;/#list&gt;<br />
关键字<br />
item_index:是list当前值的下标<br />
item_has_next:判断list是否还有值</p>
<p>用例<br />
&lt;#assign seq = ["winter", "spring", "summer", "autumn"]&gt;<br />
&lt;#list seq as x&gt;<br />
&nbsp; ${x_index + 1}. ${x}&lt;#if x_has_next&gt;,&lt;/#if&gt;<br />
&lt;/#list&gt;</p>
<p>输出<br />
&nbsp; 1. winter,<br />
&nbsp; 2. spring,<br />
&nbsp; 3. summer,<br />
&nbsp; 4. autumn&nbsp; </p>
<p><br />
<span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">include</strong></span><br />
语法<br />
&lt;#include filename&gt;<br />
or<br />
&lt;#include filename options&gt;<br />
options包含两个属性<br />
encoding=&#8221;GBK&#8221; 编码格式<br />
parse=true 是否作为ftl语法解析,默认是true，false就是以文本方式引入.注意在ftl文件里布尔值都是直接赋值的如parse=true,而不是parse=&#8221;true&#8221;<br />
用例<br />
/common/copyright.ftl包含内容<br />
Copyright 2001-2002 ${me}&lt;br&gt;<br />
All rights reserved. <br />
模板文件<br />
&lt;#assign me = "Juila Smith"&gt;<br />
&lt;h1&gt;Some test&lt;/h1&gt;<br />
&lt;p&gt;Yeah.<br />
&lt;hr&gt;<br />
&lt;#include "/common/copyright.ftl" encoding=&#8221;GBK&#8221;&gt;<br />
输出结果<br />
&lt;h1&gt;Some test&lt;/h1&gt;<br />
&lt;p&gt;Yeah.<br />
&lt;hr&gt;<br />
Copyright 2001-2002 Juila Smith<br />
All rights reserved. </p>
<p><span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">import</strong></span><br />
语法<br />
&lt;#import path as hash&gt;<br />
类似于java里的import,它导入文件，然后就可以在当前文件里使用被导入文件里的宏组件</p>
<p>用例</p>
<p>假设mylib.ftl里定义了宏copyright那么我们在其他模板页面里可以这样使用<br />
&lt;#import "/libs/mylib.ftl" as my&gt;</p>
<p>&lt;@my.copyright date="1999-2002"/&gt;</p>
<p>"my"在freemarker里被称作namespace</p>
<p>compress<br />
语法<br />
&lt;#compress&gt;<br />
&nbsp; ...<br />
&lt;/#compress&gt;<br />
用来压缩空白空间和空白的行<br />
用例<br />
&lt;#assign x = "&nbsp;&nbsp;&nbsp; moo&nbsp; \n\n&nbsp;&nbsp; "&gt;<br />
(&lt;#compress&gt;<br />
&nbsp; 1 2&nbsp; 3&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 5<br />
&nbsp; ${moo}<br />
&nbsp; test only</p>
<p>&nbsp; I said, test only</p>
<p>&lt;/#compress&gt;) <br />
输出<br />
(1 2 3 4 5<br />
moo<br />
test only<br />
I said, test only)<br />
<br />
<span style="font-size: 14pt; font-family: Comic Sans MS"><strong>escape, noescape</strong></span><br />
语法<br />
&lt;#escape identifier as expression&gt;<br />
&nbsp; ...<br />
&nbsp; &lt;#noescape&gt;...&lt;/#noescape&gt;<br />
&nbsp; ...<br />
&lt;/#escape&gt;<br />
用例<br />
主要使用在相似的字符串变量输出，比如某一个模块的所有字符串输出都必须是html安全的，这个时候就可以使用该表达式<br />
&lt;#escape x as x?html&gt;<br />
&nbsp; First name: ${firstName}<br />
&nbsp; &lt;#noescape&gt;Last name: ${lastName}&lt;/#noescape&gt;<br />
&nbsp; Maiden name: ${maidenName}<br />
&lt;/#escape&gt;<br />
相同表达式 <br />
&nbsp; First name: ${firstName?html}<br />
&nbsp; Last name: ${lastName }<br />
&nbsp; Maiden name: ${maidenName?html}<br />
assign<br />
语法<br />
&lt;#assign name=value&gt;<br />
or<br />
&lt;#assign name1=value1 name2=value2 ... nameN=valueN&gt;<br />
or<br />
&lt;#assign same as above... in namespacehash&gt;<br />
or<br />
&lt;#assign name&gt;<br />
&nbsp; capture this<br />
&lt;/#assign&gt;<br />
or<br />
&lt;#assign name in namespacehash&gt;<br />
&nbsp; capture this<br />
&lt;/#assign&gt;<br />
用例<br />
生成变量,并且给变量赋值<br />
给seasons赋予序列值<br />
&lt;#assign seasons = ["winter", "spring", "summer", "autumn"]&gt;</p>
<p>给变量test加1<br />
&lt;#assign test = test + 1&gt;</p>
<p>给my namespage 赋予一个变量bgColor,下面可以通过my.bgColor来访问这个变量<br />
&lt;#import "/mylib.ftl" as my&gt;<br />
&lt;#assign bgColor="red" in my&gt;</p>
<p>将一段输出的文本作为变量保存在x里<br />
下面的阴影部分输出的文本将被赋值给x<br />
&lt;#assign x&gt;<br />
&nbsp; &lt;#list 1..3 as n&gt;<br />
&nbsp;&nbsp;&nbsp; ${n} &lt;@myMacro /&gt;<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/#assign&gt;<br />
Number of words: ${x?word_list?size}<br />
${x}</p>
<p>&lt;#assign x&gt;Hello ${user}!&lt;/#assign&gt;&nbsp;&nbsp;&nbsp;&nbsp; error<br />
&lt;#assign x=&#8221; Hello ${user}!&#8221;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true</p>
<p>同时也支持中文赋值，如：<br />
&lt;#assign 语法&gt;<br />
&nbsp; java<br />
&lt;/#assign&gt;<br />
${语法}<br />
打印输出:<br />
java<br />
global<br />
语法<br />
&lt;#global name=value&gt;<br />
or<br />
&lt;#global name1=value1 name2=value2 ... nameN=valueN&gt;<br />
or<br />
&lt;#global name&gt;<br />
&nbsp; capture this<br />
&lt;/#global&gt;</p>
<p>全局赋值语法，利用这个语法给变量赋值，那么这个变量在所有的namespace中是可见的,如果这个变量被当前的assign语法覆盖 如&lt;#global x=2&gt; &lt;#assign x=1&gt; 在当前页面里x=2将被隐藏，或者通过${.global.x}来访问</p>
<p><span style="font-family: Comic Sans MS"><strong style="font-size: 14pt">setting</strong></span><br />
语法<br />
&lt;#setting name=value&gt;<br />
用来设置整个系统的一个环境<br />
locale<br />
number_format<br />
boolean_format<br />
date_format, time_format, datetime_format<br />
time_zone<br />
classic_compatible<br />
用例<br />
假如当前是匈牙利的设置，然后修改成美国<br />
${1.2}<br />
&lt;#setting locale="en_US"&gt;<br />
${1.2} <br />
输出<br />
1,2<br />
1.2<br />
因为匈牙利是采用&#8220;,&#8221;作为十进制的分隔符，美国是用&#8220;.&#8221;</p>
<p>&nbsp;</p>
<p><span style="font-size: 14pt; font-family: Comic Sans MS"><strong>macro, nested, return</strong></span><br />
语法</p>
<p>&lt;#macro name param1 param2 ... paramN&gt;<br />
&nbsp; ...<br />
&nbsp; &lt;#nested loopvar1, loopvar2, ..., loopvarN&gt;<br />
&nbsp; ...<br />
&nbsp; &lt;#return&gt;<br />
&nbsp; ...<br />
&lt;/#macro&gt;<br />
用例<br />
&lt;#macro test foo bar="Bar" baaz=-1&gt;<br />
&nbsp; Test text, and the params: ${foo}, ${bar}, ${baaz}<br />
&lt;/#macro&gt;<br />
&lt;@test foo="a" bar="b" baaz=5*5-2/&gt;<br />
&lt;@test foo="a" bar="b"/&gt;<br />
&lt;@test foo="a" baaz=5*5-2/&gt;<br />
&lt;@test foo="a"/&gt;<br />
输出<br />
&nbsp; Test text, and the params: a, b, 23<br />
&nbsp; Test text, and the params: a, b, -1<br />
&nbsp; Test text, and the params: a, Bar, 23<br />
&nbsp; Test text, and the params: a, Bar, -1<br />
定义循环输出的宏<br />
&lt;#macro list title items&gt;<br />
&nbsp; &lt;p&gt;${title?cap_first}:<br />
&nbsp; &lt;ul&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;#list items as x&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;li&gt;${x?cap_first}<br />
&nbsp;&nbsp;&nbsp; &lt;/#list&gt;<br />
&nbsp; &lt;/ul&gt;<br />
&lt;/#macro&gt;<br />
&lt;@list items=["mouse", "elephant", "python"] title="Animals"/&gt;<br />
输出结果 <br />
&lt;p&gt;Animals:<br />
&nbsp; &lt;ul&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;li&gt;Mouse<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;li&gt;Elephant<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;li&gt;Python<br />
&nbsp; &lt;/ul&gt;<br />
包含body的宏<br />
&lt;#macro repeat count&gt;<br />
&nbsp; &lt;#list 1..count as x&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;#nested x, x/2, x==count&gt;<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/#macro&gt;<br />
&lt;@repeat count=4 ; c halfc last&gt;<br />
&nbsp; ${c}. ${halfc}&lt;#if last&gt; Last!&lt;/#if&gt;<br />
&lt;/@repeat&gt;<br />
输出<br />
1. 0.5<br />
&nbsp; 2. 1<br />
&nbsp; 3. 1.5<br />
&nbsp; 4. 2 Last!</p>
<p>&nbsp;</p>
<p><br />
<span style="font-size: 14pt; font-family: Comic Sans MS"><strong>t, lt, rt</strong></span><br />
语法<br />
&lt;#t&gt; 去掉左右空白和回车换行</p>
<p>&lt;#lt&gt;去掉左边空白和回车换行</p>
<p>&lt;#rt&gt;去掉右边空白和回车换行</p>
<p>&lt;#nt&gt;取消上面的效果</p>
<p><br />
3一些常用方法或注意事项</p>
<p><br />
表达式转换类<br />
${expression}计算expression并输出<br />
#{ expression }数字计算#{ expression ;format}安格式输出数字format为M和m<br />
M表示小数点后最多的位数,m表示小数点后最少的位数如#{121.2322;m2M2}输出121.23</p>
<p>&nbsp;<br />
数字循环<br />
1..5 表示从1到5，原型number..number<br />
<br />
对浮点取整数<br />
${123.23?int} 输出123<br />
<br />
给变量默认值<br />
${var?default(&#8220;hello world&lt;br&gt;&#8221;)?html}如果var is null那么将会被hello world&lt;br&gt;替代<br />
<br />
判断对象是不是null<br />
&nbsp;&nbsp;&nbsp; &lt;#if mouse?exists&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mouse found<br />
&lt;#else&gt;<br />
也可以直接${mouse?if_exists})输出布尔形<br />
<br />
常用格式化日期<br />
&nbsp;openingTime必须是Date型,详细查看freemarker文档 Reference-&gt;build-in referece-&gt;build-in for date</p>
<p>${openingTime?date}<br />
${openingTime?date_time}<br />
${openingTime?time}<br />
</p>
<p><br />
添加全局共享变量数据模型<br />
在代码里的实现<br />
&nbsp;&nbsp;&nbsp; cfg = Configuration.getDefaultConfiguration();<br />
cfg.setSharedVariable("global", "you good");<br />
页面实现可以通过global指令,具体查看指令里的global部分<br />
<br />
直接调用java对象的方法<br />
${object.methed(args)} <br />
</p>
<p><br />
字符串处理(内置方法)<br />
html安全输出<br />
&#8220;abc&lt;table&gt;sdfsf&#8221;?html<br />
返回安全的html输出,替换掉html代码<br />
<br />
xml安全输出<br />
var?xml&nbsp; <br />
<br />
substring的用法<br />
&lt;#assign user=&#8221;hello jeen&#8221;&gt;<br />
${user[0]}${user[4]}<br />
${user[1..4]}<br />
输出 :<br />
ho<br />
ello <br />
<br />
类似String.split的用法<br />
&nbsp;&#8220;abc;def;ghi&#8221;?split(&#8220;;&#8221;)返回sequence<br />
将字符串按空格转化成sequence,然后取sequence的长度<br />
&nbsp;&nbsp;&nbsp;&nbsp; var?word_list&nbsp; 效果同 var?split(&#8220; &#8221;)<br />
&nbsp;var?word_list?size<br />
</p>
<p><br />
取得字符串长度<br />
var?length<br />
</p>
<p><br />
大写输出字符<br />
var?upper_case<br />
</p>
<p><br />
小写输出字符<br />
var?lower_case<br />
</p>
<p><br />
首字符大写<br />
var?cap_first<br />
</p>
<p><br />
首字符小写<br />
var?uncap_first<br />
</p>
<p><br />
去掉字符串前后空格<br />
var?trim<br />
<br />
</p>
<p>每个单词的首字符大写<br />
var?capitalize<br />
</p>
<p><br />
类似String.indexof:<br />
&nbsp;&#8220;babcdabcd&#8221;?index_of(&#8220;abc&#8221;) 返回1<br />
&nbsp;&#8220;babcdabcd&#8221;?index_of(&#8220;abc&#8221;,2) 返回5<br />
<br />
类似String.lastIndexOf<br />
&nbsp;last_index_of和String.lastIndexOf类似,同上<br />
<br />
下面两个可能在代码生成的时候使用（在引号前加&#8221;\&#8221;）<br />
j_string: 在字符串引号前加&#8221;\&#8221;<br />
&nbsp;&lt;#assign beanName = 'The "foo" bean.'&gt;<br />
&nbsp;String BEAN_NAME = "${beanName?j_string}";<br />
打印输出:<br />
&nbsp;String BEAN_NAME = "The \"foo\" bean.";<br />
js_string:<br />
<br />
&nbsp;&lt;#assign user = "Big Joe's \"right hand\"."&gt;<br />
&lt;script&gt;<br />
&nbsp; alert("Welcome ${user}!");<br />
&lt;/script&gt; <br />
打印输出<br />
&nbsp;alert("Welcome Big Joe\'s \"right hand\"!");<br />
<br />
替换字符串 replace<br />
${s?replace('ba&#8217;, 'XY&#8217; )}<br />
${s?replace('ba&#8217;, 'XY&#8217; , '规则参数&#8217;)}将s里的所有的ba替换成xy 规则参数包含: i r m s c f 具体含义如下:<br />
&#183; i: 大小写不区分.<br />
&#183; f: 只替换第一个出现被替换字符串的字符串<br />
&#183; r:&nbsp; XY是正则表达式<br />
&#183; m: Multi-line mode for regular expressions. In multi-line mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the string. By default these expressions only match at the beginning and the end of the entire string.<br />
&#183; s: Enables dotall mode for regular expressions (same as Perl singe-line mode). In dotall mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators.<br />
&#183; c: Permits whitespace and comments in regular expressions.</p>
<p><br />
在模板里对sequences和hashes初始化<br />
sequences </p>
<p>1. [&#8220;you&#8221;,&#8221;me&#8221;,&#8221;he&#8221;]<br />
2. 1..100<br />
3. [ {&#8220;Akey&#8221;:&#8221;Avalue&#8221;},{&#8220;Akey1&#8221;:&#8221;Avalue1&#8221;},<br />
{&#8220;Bkey&#8221;:&#8221;Bvalue&#8221;},{&#8220;Bkey1&#8221;:&#8221;Bvalue1&#8221;},<br />
]</p>
<p><br />
hashes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&#8220;you&#8221;:&#8221;a&#8221;,&#8221;me&#8221;:&#8221;b&#8221;,&#8221;he&#8221;:&#8221;c&#8221;}</p>
<p><br />
注释标志<br />
&lt;#--<br />
这里是注释<br />
--&gt;<br />
旧版本的freemarker采用的是&lt;#comment&gt; 注释 &lt;/#comment&gt;方法</p>
<p>sequences内置方法<br />
sequence?first<br />
返回sequence的第一个值;前提条件sequence不能是null<br />
sequence?last<br />
&nbsp;返回sequence最后一个值<br />
sequence?reverse<br />
&nbsp;反转sequence的值<br />
sequence?size<br />
&nbsp;返回sequence的大小<br />
sequence?sort<br />
&nbsp;对sequence按里面的对象toString()的结果进行排序<br />
sequence?sort_by(value)<br />
对sequence 按里面的对象的属性value进行排序<br />
如: sequence里面放入的是10 个user对象，user对象里面包含name,age等属性<br />
sequence?sort_by(name) 表示所有的user按user.name进行排序<br />
hashes内置方法<br />
hash?keys<br />
&nbsp;返回hash里的所有keys, 返回结果类型sequence<br />
hash?values<br />
&nbsp;返回hash里的所有value, 返回结果类型sequence<br />
<br />
4 freemarker在web开发中注意事项<br />
freemarker与webwork整合<br />
web中常用的几个对象<br />
Freemarker的ftl文件中直接使用内部对象:<br />
${Request ["a"]}<br />
${RequestParameters["a"]}<br />
${Session ["a"]}<br />
${Application ["a"]}<br />
${JspTaglibs ["a"]}</p>
<p>与webwork整合之后 通过配置的servlet 已经把request,session等对象置入了数据模型中<br />
在view中存在下面的对象<br />
&nbsp; 我们可以在ftl中${req}来打印req对象<br />
&#183; req - the current HttpServletRequest<br />
&#183; res - the current HttpServletResponse<br />
&#183; stack - the current OgnlValueStack<br />
&#183; ognl - the OgnlTool instance<br />
&#183; webwork - an instance of FreemarkerWebWorkUtil<br />
&#183; action - the current WebWork action<br />
&#183; exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view<br />
view中值的搜索顺序<br />
${name}将会以下面的顺序查找name值<br />
&#183; freemarker variables<br />
&#183; value stack<br />
&#183; request attributes<br />
&#183; session attributes<br />
&#183; servlet context attributes<br />
在模板里ftl里使用标签<br />
注意，如果标签的属性值是数字，那么必须采用nubmer=123方式给属性赋值<br />
JSP页面<br />
&lt;%@page contentType="text/html;charset=ISO-8859-2" language="java"%&gt;<br />
&lt;%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%&gt;<br />
&lt;%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%&gt;</p>
<p>&lt;html&gt;<br />
&nbsp; &lt;body&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;h1&gt;&lt;bean:message key="welcome.title"/&gt;&lt;/h1&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;html:errors/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;html:form action="/query"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Keyword: &lt;html:text property="keyword"/&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exclude: &lt;html:text property="exclude"/&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html:submit value="Send"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/html:form&gt;<br />
&nbsp; &lt;/body&gt;<br />
&lt;/html&gt;<br />
模板ftl页面<br />
&lt;#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]&gt;<br />
&lt;#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]&gt;</p>
<p>&lt;html&gt;<br />
&nbsp; &lt;body&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;h1&gt;&lt;@bean.message key="welcome.title"/&gt;&lt;/h1&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;@html.errors/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;@html.form action="/query"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Keyword: &lt;@html.text property="keyword"/&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exclude: &lt;@html.text property="exclude"/&gt;&lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;@html.submit value="Send"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/@html.form&gt;<br />
&nbsp; &lt;/body&gt;<br />
&lt;/html&gt; </p>
<p><br />
如何初始化共享变量<br />
1． 初始化全局共享数据模型<br />
freemark在web上使用的时候对共享数据的初始化支持的不够,不能在配置初始化的时候实现，而必须通过ftl文件来初始化全局变量。这是不能满主需求的，我们需要在servlet init的时候留出一个接口来初始化系统的共享数据<br />
具体到和webwork整合,因为本身webwork提供了整合servlet,如果要增加全局共享变量，可以通过修改 com.opensymphony.webwork.views.freemarker.FreemarkerServlet来实现,我们可以在这个 servlet初始化的时候来初始化全局共享变量<br />
与webwork整合配置<br />
配置web.xml<br />
&lt;servlet&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;freemarker&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;com.opensymphony.webwork.views.freemarker.FreemarkerServlet&lt;/servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;TemplatePath&lt;/param-name&gt;<br />
&lt;param-value&gt;/&lt;/param-value&gt;<br />
&lt;!—模板载入文件夹，这里相对context root，递归获取该文件夹下的所有模板--&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;NoCache&lt;/param-name&gt; &lt;!—是否对模板缓存--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;true&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;ContentType&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;text/html&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&lt;param-name&gt;template_update_delay&lt;/param-name&gt;<br />
&lt;!—模板更新时间,0表示每次都更新,这个适合开发时候--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;0&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;default_encoding&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;GBK&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;number_format&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;0.##########&lt;/param-value&gt;&lt;!—数字显示格式--&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
&nbsp; &lt;/servlet&gt;<br />
&nbsp; &lt;servlet-mapping&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;freemarker&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.ftl&lt;/url-pattern&gt;<br />
&nbsp; &lt;/servlet-mapping&gt;</p>
<p>5高级方法<br />
自定义方法<br />
${timer("yyyy-MM-dd H:mm:ss", x)}<br />
${timer("yyyy-MM-dd ", x)}</p>
<p>在模板中除了可以通过对象来调用方法外（${object.methed(args)}）也可以直接调用java实现的方法，java类必须实现接口TemplateMethodModel的方法exec(List args). 下面以把毫秒的时间转换成按格式输出的时间为例子<br />
public class LongToDate implements TemplateMethodModel {<br />
&nbsp;&nbsp; <br />
public TemplateModel exec(List args) throws TemplateModelException {<br />
SimpleDateFormat mydate = new SimpleDateFormat((String) args.get(0)));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mydate.format(new Date(Long.parseLong((String)args.get(1)));<br />
&nbsp;&nbsp;&nbsp; }<br />
} <br />
将LongToDate对象放入到数据模型中<br />
root.put("timer", new IndexOfMethod());<br />
ftl模板里使用<br />
&lt;#assign x = "123112455445"&gt;<br />
${timer("yyyy-MM-dd H:mm:ss", x)}<br />
${timer("yyyy-MM-dd ", x)}</p>
<p>输出<br />
2001-10-12 5:21:12<br />
2001-10-12</p>
<p>自定义 Transforms<br />
实现自定义的&lt;@transform&gt;文本或表达式&lt;/@transform&gt;的功能,允许对中间的最终文本进行解析转换</p>
<p>例子：实现&lt;@upcase&gt;str&lt;/@upcase&gt; 将str转换成STR 的功能</p>
<p>代码如下：<br />
import java.io.*;<br />
import java.util.*;<br />
import freemarker.template.TemplateTransformModel;</p>
<p>class UpperCaseTransform implements TemplateTransformModel {</p>
<p>&nbsp;&nbsp;&nbsp; public Writer getWriter(Writer out, Map args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new UpperCaseWriter(out);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private class UpperCaseWriter extends Writer {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private Writer out;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UpperCaseWriter (Writer out) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.out = out;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void write(char[] cbuf, int off, int len)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.write(new String(cbuf, off, len).toUpperCase());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void flush() throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.flush();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void close() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
} <br />
然后将此对象put到数据模型中<br />
root.put("upcase", new UpperCaseTransform());</p>
<p>在view(ftl)页面中可以如下方式使用</p>
<p>&lt;@upcase&gt;<br />
hello world<br />
&lt;/@upcase&gt;</p>
<p>打印输出:<br />
HELLO WORLD</p>
<img src ="http://www.blogjava.net/jzone/aggbug/291812.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2009-08-19 18:16 <a href="http://www.blogjava.net/jzone/articles/291812.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FreeMarker 中常见的 StringIndexOutOfBoundsException</title><link>http://www.blogjava.net/jzone/articles/286070.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Thu, 09 Jul 2009 05:10:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/286070.html</guid><description><![CDATA[关于这个问题，跟undefined差不多常见。原因就是数据源为空字符（而非空）。<br /><br /><h1>500 Servlet Exception</h1><code></code><pre>java.lang.StringIndexOutOfBoundsException: String index out of range: 1
	at java.lang.String.substring(String.java:1935)
	at yixun.wap.filter.ReplaceTextStream.replaceContent(ReplaceTextFilter.java:32)
	at yixun.wap.filter.ReplaceTextFilter.doFilter(ReplaceTextFilter.java:81)
	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:73)
	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:167)
	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:226)
	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:263)
	at com.caucho.server.port.TcpConnection.run(TcpConnection.java:477)
	at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:591)
	at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:619)
</pre><img src ="http://www.blogjava.net/jzone/aggbug/286070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2009-07-09 13:10 <a href="http://www.blogjava.net/jzone/articles/286070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse 安装 FreeMarker编辑器</title><link>http://www.blogjava.net/jzone/articles/286068.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Thu, 09 Jul 2009 04:57:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/286068.html</guid><description><![CDATA[
		<p>
				<br />要使用FreeMarker，话不多说，肯定先要给MyEclipse装上FreeMarker的编辑插件，这样代码才能高亮显示啊。<br /><br /><br />打开菜单项 Help -&gt; Software updates -&gt; Find and install.... <br /><br />选择单选项 "Search for new features to install". <br />点击 Add Update Site..., 输入 "FreeMarker"  作为名字以及 "http://www.freemarker.org/eclipse/update" 作为更新的地址 <br />选中复选框 "FreeMarker" 点击下一步或完成按钮根据提示完成插件的安装 <br /><br />要想使用FreeMarker开发了，那还需要网上下载freemarker.jar包</p>
<img src ="http://www.blogjava.net/jzone/aggbug/286068.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2009-07-09 12:57 <a href="http://www.blogjava.net/jzone/articles/286068.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FreeMarker 中最常见的 undefined</title><link>http://www.blogjava.net/jzone/articles/286013.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Thu, 09 Jul 2009 01:50:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/286013.html</guid><description><![CDATA[
		<h1>500 Servlet Exception</h1>
		<code>
		</code>
		<pre>freemarker.core.InvalidReferenceException: Expression s.expect is undefined
on line 7, column 11 in news/prize/open/ssc.ftl.
	at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:124)
	at freemarker.core.Expression.getStringValue(Expression.java:118)
	at freemarker.core.Expression.getStringValue(Expression.java:93)
	at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.MixedContent.accept(MixedContent.java:92)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:179)
	at freemarker.core.Environment.visit(Environment.java:416)
	at freemarker.core.IteratorBlock.accept(IteratorBlock.java:102)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.MixedContent.accept(MixedContent.java:92)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.Environment.visit(Environment.java:394)
	at freemarker.core.BodyInstruction.accept(BodyInstruction.java:93)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.MixedContent.accept(MixedContent.java:92)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.Environment.visit(Environment.java:298)
	at freemarker.core.CompressedBlock.accept(CompressedBlock.java:73)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.MixedContent.accept(MixedContent.java:92)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.EscapeBlock.accept(EscapeBlock.java:84)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.Macro$Context.runMacro(Macro.java:168)
	at freemarker.core.Environment.visit(Environment.java:602)
	at freemarker.core.UnifiedCall.accept(UnifiedCall.java:106)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.MixedContent.accept(MixedContent.java:92)
	at freemarker.core.Environment.visit(Environment.java:209)
	at freemarker.core.Environment.process(Environment.java:189)
	at freemarker.template.Template.process(Template.java:237)
	at yixun.wap.freemarker.FreemarkerDo.doMark(FreemarkerDo.java:47)
	at _jsp._page._news._prize._open._ssc__jsp._jspService(page/news/prize/open/ssc.jsp:41)
	at com.caucho.jsp.JavaPage.service(JavaPage.java:61)
	at com.caucho.jsp.Page.pageservice(Page.java:586)
	at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:190)
	at yixun.wap.filter.ReplaceTextFilter.doFilter(ReplaceTextFilter.java:77)
	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:73)
	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:167)
	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:226)
	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:263)
	at com.caucho.server.port.TcpConnection.run(TcpConnection.java:477)
	at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:591)
	at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:513)
	at java.lang.Thread.run(Thread.java:619)<br /><br /><br />注：<br />由于freemarker强烈不支持null，所以这个问题呢，多半就是JSP（或抛数据源的地方）数据没有正确的传过来。究其原因，不在ftl模板。
MyEclipse控制台输出：一看知道哪个页面，哪行错了，so easy……  O(∩_∩)O~<br />[09:44:50.546] Compiling _jsp/_page/_news/_prize/_open/_ssc__jsp.java<br />[ERROR] <br />Expression s.expect is undefined on line 7, column 11 in news/prize/open/ssc.ftl.<br />The problematic instruction:<br />----------<br />==&gt; ${s.expect} [on line 7, column 9 in news/prize/open/ssc.ftl]<br /> in user-directive f.page [on line 3, column 1 in news/prize/open/ssc.ftl]<br />----------</pre>
		<pre>Java backtrace for programmers:<br />----------<br />freemarker.core.InvalidReferenceException: Expression s.expect is undefined on line 7, column 11 in news/prize/open/ssc.ftl.<br /> at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:124)<br /> at freemarker.core.Expression.getStringValue(Expression.java:118)<br />……<br />……</pre>
<img src ="http://www.blogjava.net/jzone/aggbug/286013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2009-07-09 09:50 <a href="http://www.blogjava.net/jzone/articles/286013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>freemarker 语法基础（转）</title><link>http://www.blogjava.net/jzone/articles/284300.html</link><dc:creator>Gavin.lee</dc:creator><author>Gavin.lee</author><pubDate>Fri, 26 Jun 2009 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/jzone/articles/284300.html</guid><description><![CDATA[<div class="blog_content">
<p>http://freemarker.org/docs/index.html &nbsp; 官方手册<br />
</p>
<p>FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成:<br />
<strong>1,文本:直接输出的部分<br />
2,注释:&lt;#--
...
--&gt;格式部分,不会输出<br />
3,插值:即${...}或#{...}格式的部分,将使用数据模型中的部分替代输出<br />
4,FTL指令:FreeMarker指定,和HTML标记类似,名字前加#予以区分,不会输出</strong></p>
<p>下面是一个FreeMarker模板的例子,包含了以上所说的4个部分<br />
&lt;html&gt;&lt;br&gt;<br />
&lt;head&gt;&lt;br&gt;<br />
&lt;title&gt;Welcome!&lt;/title&gt;&lt;br&gt;<br />
&lt;/head&gt;&lt;br&gt;<br />
&lt;body&gt;&lt;br&gt;<br />
&lt;#--
注释部分 --&gt;&lt;br&gt;<br />
&lt;#-- 下面使用插值 --&gt;<br />
&lt;h1&gt;Welcome ${user}
!&lt;/h1&gt;&lt;br&gt;<br />
&lt;p&gt;We have these
animals:&lt;br&gt;<br />
&lt;u1&gt;&lt;br&gt;<br />
&lt;#-- 使用FTL指令
--&gt;<br />
&lt;#list animals as being&gt;&lt;br&gt;<br />
&nbsp;&nbsp; &lt;li&gt;${being.name}
for ${being.price}
Euros&lt;br&gt;<br />
&lt;#list&gt;&lt;br&gt;<br />
&lt;u1&gt;&lt;br&gt;<br />
&lt;/body&gt;&lt;br&gt;<br />
&lt;/html&gt;</p>
<p><strong><span style="font-size: large;">1, FTL指令规则</span></strong></p>
<p>在FreeMarker中,使用FTL标签来使用指令,FreeMarker有3种FTL标签,这和HTML标签是完全类似的.<br />
1,开始标签:&lt;#directivename
parameter&gt;<br />
2,结束标签:&lt;/#directivename&gt;<br />
3,空标签:&lt;#directivename
parameter/&gt;</p>
<p>实际上,使用标签时前面的符号#也可能变成@,如果该指令是一个用户指令而不是系统内建指令时,应将#符号改成@符号.<br />
使用FTL标签时,应该有正确的嵌套,而不是交叉使用,这和XML标签的用法完全一样.如果全用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息.FreeMarker会忽略FTL标签中的空白字符.值得注意的是&lt;
, /&gt; 和指令之间不允许有空白字符.</p>
<p><strong><span style="font-size: large;">2, 插值规则</span></strong></p>
<p>FreeMarker的插值有如下两种类型:1,通用插值${expr};2,数字格式化插值:#{expr}或#{expr;format}</p>
<p><strong><span style="font-size: small;">2.1 通用插值</span></strong></p>
<p>对于通用插值,又可以分为以下4种情况:<br />
1,插值结果为字符串值:直接输出表达式结果<br />
2,插值结果为数字值:根据默认格式(由#setting指令设置)将表达式结果转换成文本输出.可以使用内建的字符串函数格式化单个插值,如下面的例子:<br />
&lt;#settion
number_format="currency"/&gt;<br />
&lt;#assign
answer=42/&gt;<br />
${answer}<br />
${answer?string} &lt;#-- the same as ${answer}
--&gt;<br />
${answer?string.number}<br />
${answer?string.currency}<br />
${answer?string.percent}<br />
${answer}<br />
输出结果是:<br />
$42.00<br />
$42.00<br />
42<br />
$42.00<br />
4,200%<br />
3,插值结果为日期值:根据默认格式(由#setting指令设置)将表达式结果转换成文本输出.可以使用内建的字符串函数格式化单个插值,如下面的例子:<br />
${lastUpdated?string("yyyy-MM-dd
HH:mm:ss zzzz")}<br />
${lastUpdated?string("EEE, MMM d,
''yy")}<br />
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a
'('zzz')'")}<br />
输出结果是:<br />
2008-04-08 08:08:08 Pacific Daylight Time<br />
Tue, Apr
8, '03<br />
Tuesday, April 08, 2003, 08:08:08 PM
(PDT)<br />
4,插值结果为布尔值:根据默认格式(由#setting指令设置)将表达式结果转换成文本输出.可以使用内建的字符串函数格式化单个插值,如下面的例子:<br />
&lt;#assign
foo=true/&gt;<br />
${foo?string("yes", "no")}<br />
输出结果是:<br />
yes</p>
<p><strong><span style="font-size: small;">2.2 数字格式化插值</span></strong></p>
<p>数字格式化插值可采用#{expr;format}形式来格式化数字,其中format可以是:<br />
mX:小数部分最小X位<br />
MX:小数部分最大X位<br />
如下面的例子:<br />
&lt;#assign
x=2.582/&gt;<br />
&lt;#assign y=4/&gt;<br />
#{x; M2} &lt;#-- 输出2.58 --&gt;<br />
#{y;
M2} &lt;#-- 输出4 --&gt;<br />
#{x; m2} &lt;#-- 输出2.6 --&gt;<br />
#{y; m2} &lt;#--
输出4.0 --&gt;<br />
#{x; m1M2} &lt;#-- 输出2.58 --&gt;<br />
#{x; m1M2} &lt;#-- 输出4.0
--&gt;</p>
<p><strong><span style="font-size: large;">3, 表达式</span></strong></p>
<p>表达式是FreeMarker模板的核心功能,表达式放置在插值语法${}之中时,表明需要输出表达式的值;表达式语法也可与FreeMarker标签结合,用于控制输出.实际上FreeMarker的表达式功能非常强大,它不仅支持直接指定值,输出变量值,也支持字符串格式化输出和集合访问等功能.</p>
<p><strong><span style="font-size: small;">3.1 直接指定值</span></strong></p>
<p>使用直接指定值语法让FreeMarker直接输出插值中的值,而不是输出变量值.直接指定值可以是字符串,数值,布尔值,集合和MAP对象.</p>
<p>1,字符串<br />
直接指定字符串值使用单引号或双引号限定,如果字符串值中包含特殊字符需要转义,看下面的例子:<br />
${"我的文件保存在C:\\盘"}<br />
${'我名字是\"annlee\"'}<br />
输出结果是:
<br />
我的文件保存在C:\盘<br />
我名字是"annlee"</p>
<p>FreeMarker支持如下转义字符:<br />
\";双引号(u0022)<br />
\';单引号(u0027)<br />
\\;反斜杠(u005C)<br />
\n;换行(u000A)<br />
\r;回车(u000D)<br />
\t;Tab(u0009)<br />
\b;退格键(u0008)<br />
\f;Form
feed(u000C)<br />
\l;&lt;<br />
\g;&gt;<br />
\a;&amp;<br />
\{;{<br />
\xCode;直接通过4位的16进制数来指定Unicode码,输出该unicode码对应的字符.</p>
<p>如果某段文本中包含大量的特殊符号,FreeMarker提供了另一种特殊格式:可以在指定字符串内容的引号前增加r标记,在r标记后的文件将会直接输出.看如下代码:<br />
${r"${foo}"}<br />
${r"C:\foo\bar"}<br />
输出结果是:<br />
${foo}<br />
C:\foo\bar</p>
<p>2,数值<br />
表达式中的数值直接输出,不需要引号.小数点使用"."分隔,不能使用分组","符号.FreeMarker目前还不支持科学计数法,所以"1E3"是错误的.在FreeMarker表达式中使用数值需要注意以下几点:<br />
1,数值不能省略小数点前面的0,所以".5"是错误的写法<br />
2,数值8
, +8 , 8.00都是相同的</p>
<p>3,布尔值<br />
直接使用true和false,不使用引号.</p>
<p>4,集合<br />
集合以方括号包括,各集合元素之间以英文逗号","分隔,看如下的例子:<br />
&lt;#list ["星期一", "星期二", "星期三",
"星期四", "星期五", "星期六", "星期天"] as
x&gt;<br />
${x}<br />
&lt;/#list&gt;<br />
输出结果是:<br />
星期一<br />
星期二<br />
星期三<br />
星期四<br />
星期五<br />
星期六<br />
星期天</p>
<p>除此之外,集合元素也可以是表达式,例子如下:<br />
[2 + 2, [1, 2, 3, 4], "whatnot"]</p>
<p>还可以使用数字范围定义数字集合,如2..5等同于[2, 3, 4,
5],但是更有效率.注意,使用数字范围来定义集合时无需使用方括号,数字范围也支持反递增的数字范围,如5..2</p>
<p>5,Map对象<br />
Map对象使用花括号包括,Map中的key-value对之间以英文冒号":"分隔,多组key-value对之间以英文逗号","分隔.下面是一个例子:<br />
{"语文":78,
"数学":80}<br />
Map对象的key和value都是表达式,但是key必须是字符串</p>
<p><strong><span style="font-size: small;">3.2 输出变量值</span></strong></p>
<p>FreeMarker的表达式输出变量时,这些变量可以是顶层变量,也可以是Map对象中的变量,还可以是集合中的变量,并可以使用点(.)语法来访问Java对象的属性.下面分别讨论这些情况</p>
<p>1,顶层变量<br />
所谓顶层变量就是直接放在数据模型中的值,例如有如下数据模型:<br />
Map root = new HashMap();&nbsp;&nbsp;
//创建数据模型<br />
root.put("name","annlee");&nbsp;&nbsp; //name是一个顶层变量</p>
<p>对于顶层变量,直接使用${variableName}来输出变量值,变量名只能是字母,数字,下划线,$,@和#的组合,且不能以数字开头号.为了输出上面的name的值,可以使用如下语法:<br />
${name}</p>
<p>2,输出集合元素<br />
如果需要输出集合元素,则可以根据集合元素的索引来输出集合元素,集合元素的索引以方括号指定.假设有索引:<br />
["星期一","星期二","星期三","星期四","星期五","星期六","星期天"].该索引名为week,如果需要输出星期三,则可以使用如下语法:<br />
${week[2]}&nbsp;&nbsp;
//输出第三个集合元素</p>
<p>此外,FreeMarker还支持返回集合的子集合,如果需要返回集合的子集合,则可以使用如下语法:<br />
week[3..5]&nbsp;&nbsp;
//返回week集合的子集合,子集合中的元素是week集合中的第4-6个元素</p>
<p>3,输出Map元素<br />
这里的Map对象可以是直接HashMap的实例,甚至包括JavaBean实例,对于JavaBean实例而言,我们一样可以把其当成属性为key,属性值为value的Map实例.为了输出Map元素的值,可以使用点语法或方括号语法.假如有下面的数据模型:<br />
Map
root = new HashMap();<br />
Book book = new Book();<br />
Author author = new
Author();<br />
author.setName("annlee");<br />
author.setAddress("gz");<br />
book.setName("struts2");<br />
book.setAuthor(author);<br />
root.put("info","struts");<br />
root.put("book",
book);</p>
<p>为了访问数据模型中名为struts2的书的作者的名字,可以使用如下语法:<br />
book.author.name&nbsp;&nbsp;&nbsp;
//全部使用点语法<br />
book["author"].name<br />
book.author["name"]&nbsp;&nbsp;&nbsp;
//混合使用点语法和方括号语法<br />
book["author"]["name"]&nbsp;&nbsp; //全部使用方括号语法</p>
<p>使用点语法时,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字可以是任意表达式的结果.</p>
<p><strong><span style="font-size: small;">3.3, 字符串操作</span></strong></p>
<p>FreeMarker的表达式对字符串操作非常灵活,可以将字符串常量和变量连接起来,也可以返回字符串的子串等.</p>
<p>字符串连接有两种语法:<br />
1,使用${..}或#{..}在字符串常量部分插入表达式的值,从而完成字符串连接.<br />
2,直接使用连接运算符+来连接字符串</p>
<p>例如有如下数据模型:<br />
Map root = new HashMap();
root.put("user","annlee");<br />
下面将user变量和常量连接起来:<br />
${"hello, ${user}!"}&nbsp;&nbsp;
//使用第一种语法来连接<br />
${"hello, " + user + "!"}
//使用+号来连接<br />
上面的输出字符串都是hello,annlee!,可以看出这两种语法的效果完全一样.</p>
<p>值得注意的是,${..}只能用于文本部分,不能用于表达式,下面的代码是错误的:<br />
&lt;#if
${isBig}&gt;Wow!&lt;/#if&gt;<br />
&lt;#if
"${isBig}"&gt;Wow!&lt;/#if&gt;<br />
应该写成:&lt;#if isBig&gt;Wow!&lt;/#if&gt;</p>
<p>截取子串可以根据字符串的索引来进行,截取子串时如果只指定了一个索引值,则用于取得字符串中指定索引所对应的字符;如果指定两个索引值,则返回两个索引中间的字符串子串.假如有如下数据模型:<br />
Map
root = new HashMap();
root.put("book","struts2,freemarker");<br />
可以通过如下语法来截取子串:<br />
${book[0]}${book[4]}&nbsp;&nbsp;
//结果是su<br />
${book[1..4]}&nbsp;&nbsp;&nbsp;&nbsp; //结果是tru</p>
<p><strong><span style="font-size: small;">3.4 集合连接运算符</span></strong></p>
<p>这里所说的集合运算符是将两个集合连接成一个新的集合,连接集合的运算符是+,看如下的例子:<br />
&lt;#list ["星期一","星期二","星期三"]
+ ["星期四","星期五","星期六","星期天"] as x&gt;<br />
${x}<br />
&lt;/#list&gt;<br />
输出结果是:星期一 星期二
星期三 星期四 星期五 星期六 星期天</p>
<p><strong><span style="font-size: small;">3.5 Map连接运算符</span></strong></p>
<p>Map对象的连接运算符也是将两个Map对象连接成一个新的Map对象,Map对象的连接运算符是+,如果两个Map对象具有相同的key,则右边的值替代左边的值.看如下的例子:<br />
&lt;#assign
scores = {"语文":86,"数学":78} +
{"数学":87,"Java":93}&gt;<br />
语文成绩是${scores.语文}<br />
数学成绩是${scores.数学}<br />
Java成绩是${scores.Java}<br />
输出结果是:<br />
语文成绩是86<br />
数学成绩是87<br />
Java成绩是93</p>
<p><strong><span style="font-size: small;">3.6 算术运算符</span></strong></p>
<p>FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %
看如下的代码:<br />
&lt;#assign x=5&gt;<br />
${ x * x - 100 }<br />
${ x /2 }<br />
${ 12 %10
}<br />
输出结果是:<br />
-75&nbsp;&nbsp; 2.5&nbsp;&nbsp; 2</p>
<p>在表达式中使用算术运算符时要注意以下几点:<br />
1,运算符两边的运算数字必须是数字<br />
2,使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3
+ "5"},结果是:35</p>
<p>使用内建的int函数可对数值取整,如:<br />
&lt;#assign x=5&gt;<br />
${ (x/2)?int }<br />
${ 1.1?int
}<br />
${ 1.999?int }<br />
${ -1.1?int }<br />
${ -1.999?int }<br />
结果是:2 1 1 -1 -1</p>
<p><strong><span style="font-size: small;">3.7 比较运算符</span></strong></p>
<p>表达式中支持的比较运算符有如下几个:<br />
1,=或者==:判断两个值是否相等.<br />
2,!=:判断两个值是否不等.<br />
3,&gt;或者gt:判断左边值是否大于右边值<br />
4,&gt;=或者gte:判断左边值是否大于等于右边值<br />
5,&lt;或者lt:判断左边值是否小于右边值<br />
6,&lt;=或者lte:判断左边值是否小于等于右边值</p>
<p>注意:=和!=可以用于字符串,数值和日期来比较是否相等,但=和!=两边必须是相同类型的值,否则会产生错误,而且FreeMarker是精确比较,"x","x
","X"是不等的.其它的运行符可以作用于数字和日期,但不能作用于字符串,大部分的时候,使用gt等字母运算符代替&gt;会有更好的效果,因为FreeMarker会把&gt;解释成FTL标签的结束字符,当然,也可以使用括号来避免这种情况,如:&lt;#if
(x&gt;y)&gt;</p>
<p><strong><span style="font-size: small;">3.8 逻辑运算符</span></strong></p>
<p>逻辑运算符有如下几个:<br />
逻辑与:&amp;&amp;<br />
逻辑或:||<br />
逻辑非:!<br />
逻辑运算符只能作用于布尔值,否则将产生错误</p>
<p><strong><span style="font-size: small;">3.9 内建函数</span></strong></p>
<p>FreeMarker还提供了一些内建函数来转换输出,可以在任何变量后紧跟?,?后紧跟内建函数,就可以通过内建函数来轮换输出变量.下面是常用的内建的字符串函数:<br />
html:对字符串进行HTML编码<br />
cap_first:使字符串第一个字母大写<br />
lower_case:将字符串转换成小写<br />
upper_case:将字符串转换成大写<br />
trim:去掉字符串前后的空白字符</p>
<p>下面是集合的常用内建函数<br />
size:获取序列中元素的个数</p>
<p>下面是数字值的常用内建函数<br />
int:取得数字的整数部分,结果带符号</p>
<p>例如:<br />
&lt;#assign test="Tom &amp;
Jerry"&gt;<br />
${test?html}<br />
${test?upper_case?html}<br />
结果是:Tom &amp;amp;
Jerry&nbsp;&nbsp; TOM &amp;amp; JERRY</p>
<p><strong><span style="font-size: small;">3.10 空值处理运算符</span></strong></p>
<p>FreeMarker对空值的处理非常严格,FreeMarker的变量必须有值,没有被赋值的变量就会抛出异常,因为FreeMarker未赋值的变量强制出错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误.这里所说的空值,实际上也包括那些并不存在的变量,对于一个Java的null值而言,我们认为这个变量是存在的,只是它的值为null,但对于FreeMarker模板而言,它无法理解null值,null值和不存在的变量完全相同.</p>
<p>为了处理缺失变量,FreeMarker提供了两个运算符:<br />
!:指定缺失变量的默认值<br />
??:判断某个变量是否存在</p>
<p>其中,!运算符的用法有如下两种:<br />
variable!或variable!defaultValue,第一种用法不给缺失的变量指定默认值,表明默认值是空字符串,长度为0的集合,或者长度为0的Map对象.</p>
<p>使用!指定默认值时,并不要求默认值的类型和变量类型相同.使用??运算符非常简单,它总是返回一个布尔值,用法为:variable??,如果该变量存在,返回true,否则返回false</p>
<p><strong><span style="font-size: small;">3.11 运算符的优先级</span></strong></p>
<p>FreeMarker中的运算符优先级如下(由高到低排列):<br />
1,一元运算符:!<br />
2,内建函数:?<br />
3,乘除法:*, / ,
%<br />
4,加减法:- , +<br />
5,比较:&gt; , &lt; , &gt;= , &lt;= (lt , lte , gt ,
gte)<br />
6,相等:== , = , !=<br />
7,逻辑与:&amp;&amp;<br />
8,逻辑或:||<br />
9,数字范围:..</p>
<p>实际上,我们在开发过程中应该使用括号来严格区分,这样的可读性好,出错少</p>
<p><strong><span style="font-size: large;">4 FreeMarker的常用指令</span></strong></p>
<p>FreeMarker的FTL指令也是模板的重要组成部分,这些指令可实现对数据模型所包含数据的抚今迭代,分支控制.除此之外,还有一些重要的功能,也是通过FTL指令来实现的.</p>
<p><strong><span style="font-size: small;">4.1 if指令</span></strong></p>
<p>这是一个典型的分支控制指令,该指令的作用完全类似于Java语言中的if,if指令的语法格式如下:<br />
&lt;#if
condition&gt;...<br />
&lt;#elseif condition&gt;...<br />
&lt;#elseif
condition&gt;...<br />
&lt;#else&gt; ...<br />
&lt;/#if&gt;</p>
<p>例子如下:<br />
&lt;#assign age=23&gt;<br />
&lt;#if (age&gt;60)&gt;老年人<br />
&lt;#elseif
(age&gt;40)&gt;中年人<br />
&lt;#elseif (age&gt;20)&gt;青年人<br />
&lt;#else&gt;
少年人<br />
&lt;/#if&gt;<br />
输出结果是:青年人<br />
上面的代码中的逻辑表达式用括号括起来主要是因为里面有&gt;符号,由于FreeMarker会将&gt;符号当成标签的结束字符,可能导致程序出错,为了避免这种情况,我们应该在凡是出现这些符号的地方都使用括号.</p>
<p><strong><span style="font-size: small;">4.2 switch , case , default ,
break指令</span></strong></p>
<p>这些指令显然是分支指令,作用类似于Java的switch语句,switch指令的语法结构如下:<br />
&lt;#switch
value&gt;<br />
&lt;#case refValue&gt;...&lt;#break&gt;<br />
&lt;#case
refValue&gt;...&lt;#break&gt;<br />
&lt;#default&gt;...<br />
&lt;/#switch&gt;</p>
<p><strong><span style="font-size: small;">4.3 list, break指令</span></strong></p>
<p>list指令是一个迭代输出指令,用于迭代输出数据模型中的集合,list指令的语法格式如下:<br />
&lt;#list sequence as
item&gt;<br />
...<br />
&lt;/#list&gt;<br />
上面的语法格式中,sequence就是一个集合对象,也可以是一个表达式,但该表达式将返回一个集合对象,而item是一个任意的名字,就是被迭代输出的集合元素.此外,迭代集合对象时,还包含两个特殊的循环变量:<br />
item_index:当前变量的索引值<br />
item_has_next:是否存在下一个对象<br />
也可以使用&lt;#break&gt;指令跳出迭代</p>
<p>例子如下:<br />
&lt;#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as
x&gt;<br />
${x_index + 1}.${x}&lt;#if x_has_next&gt;,&lt;/if&gt;<br />
&lt;#if
x="星期四"&gt;&lt;#break&gt;&lt;/#if&gt;<br />
&lt;/#list&gt;</p>
<p><strong><span style="font-size: small;">4.4 include指令</span></strong></p>
<p>include指令的作用类似于JSP的包含指令,用于包含指定页.include指令的语法格式如下:<br />
&lt;#include filename
[options]&gt;<br />
在上面的语法格式中,两个参数的解释如下:<br />
filename:该参数指定被包含的模板文件<br />
options:该参数可以省略,指定包含时的选项,包含encoding和parse两个选项,其中encoding指定包含页面时所用的解码集,而parse指定被包含文件是否作为FTL文件来解析,如果省略了parse选项值,则该选项默认是true.</p>
<p><strong><span style="font-size: small;">4.5 import指令</span></strong></p>
<p>该指令用于导入FreeMarker模板中的所有变量,并将该变量放置在指定的Map对象中,import指令的语法格式如下:<br />
&lt;#import
"/lib/common.ftl" as
com&gt;<br />
上面的代码将导入/lib/common.ftl模板文件中的所有变量,交将这些变量放置在一个名为com的Map对象中.</p>
<p><strong><span style="font-size: small;">4.6 noparse指令</span></strong></p>
<p>noparse指令指定FreeMarker不处理该指定里包含的内容,该指令的语法格式如下:<br />
&lt;#noparse&gt;...&lt;/#noparse&gt;</p>
<p>看如下的例子:<br />
&lt;#noparse&gt;<br />
&lt;#list books as book&gt;<br />
&nbsp;&nbsp;
&lt;tr&gt;&lt;td&gt;${book.name}&lt;td&gt;作者:${book.author}<br />
&lt;/#list&gt;<br />
&lt;/#noparse&gt;<br />
输出如下:<br />
&lt;#list
books as book&gt;<br />
&nbsp;&nbsp;
&lt;tr&gt;&lt;td&gt;${book.name}&lt;td&gt;作者:${book.author}<br />
&lt;/#list&gt;</p>
<p><strong><span style="font-size: small;">4.7 escape ,
noescape指令</span></strong></p>
<p>escape指令导致body区的插值都会被自动加上escape表达式,但不会影响字符串内的插值,只会影响到body内出现的插值,使用escape指令的语法格式如下:<br />
&lt;#escape
identifier as
expression&gt;...<br />
&lt;#noescape&gt;...&lt;/#noescape&gt;<br />
&lt;/#escape&gt;</p>
<p>看如下的代码:<br />
&lt;#escape x as x?html&gt;<br />
First name:${firstName}<br />
Last
name:${lastName}<br />
Maiden
name:${maidenName}<br />
&lt;/#escape&gt;<br />
上面的代码等同于:<br />
First
name:${firstName?html}<br />
Last name:${lastName?html}<br />
Maiden
name:${maidenName?html}</p>
<p>escape指令在解析模板时起作用而不是在运行时起作用,除此之外,escape指令也嵌套使用,子escape继承父escape的规则,如下例子:<br />
&lt;#escape
x as x?html&gt;<br />
Customer Name:${customerName}<br />
Items to
ship;<br />
&lt;#escape x as itemCodeToNameMap[x]&gt;<br />
&nbsp;&nbsp; ${itemCode1}<br />
&nbsp;&nbsp;
${itemCode2}<br />
&nbsp;&nbsp; ${itemCode3}<br />
&nbsp;&nbsp;
${itemCode4}<br />
&lt;/#escape&gt;<br />
&lt;/#escape&gt;<br />
上面的代码类似于:<br />
Customer
Name:${customerName?html}<br />
Items to
ship;<br />
${itemCodeToNameMap[itemCode1]?html}<br />
${itemCodeToNameMap[itemCode2]?html}<br />
${itemCodeToNameMap[itemCode3]?html}<br />
${itemCodeToNameMap[itemCode4]?html}</p>
<p>对于放在escape指令中所有的插值而言,这此插值将被自动加上escape表达式,如果需要指定escape指令中某些插值无需添加escape表达式,则应该使用noescape指令,放在noescape指令中的插值将不会添加escape表达式.</p>
<p><strong><span style="font-size: small;">4.8 assign指令</span></strong></p>
<p>assign指令在前面已经使用了多次,它用于为该模板页面创建或替换一个顶层变量,assign指令的用法有多种,包含创建或替换一个顶层变量,或者创建或替换多个变量等,它的最简单的语法如下:&lt;#assign
name=value [in
namespacehash]&gt;,这个用法用于指定一个名为name的变量,该变量的值为value,此外,FreeMarker允许在使用assign指令里增加in子句,in子句用于将创建的name变量放入namespacehash命名空间中.</p>
<p>assign指令还有如下用法:&lt;#assign name1=value1 name2=value2 ... nameN=valueN [in
namespacehash]&gt;,这个语法可以同时创建或替换多个顶层变量,此外,还有一种复杂的用法,如果需要创建或替换的变量值是一个复杂的表达式,则可以使用如下语法格式:&lt;#assign
name [in namespacehash]&gt;capture
this&lt;/#assign&gt;,在这个语法中,是指将assign指令的内容赋值给name变量.如下例子:<br />
&lt;#assign
x&gt;<br />
&lt;#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as
n&gt;<br />
${n}<br />
&lt;/#list&gt;<br />
&lt;/#assign&gt;<br />
${x}<br />
上面的代码将产生如下输出:星期一
星期二 星期三 星期四 星期五 星期六 星期天</p>
<p>虽然assign指定了这种复杂变量值的用法,但是我们也不要滥用这种用法,如下例子:&lt;#assign x&gt;Hello
${user}!&lt;/#assign&gt;,以上代码改为如下写法更合适:&lt;#assign x="Hello ${user}!"&gt;</p>
<p><strong><span style="font-size: small;">4.9 setting指令</span></strong></p>
<p>该指令用于设置FreeMarker的运行环境,该指令的语法格式如下:&lt;#setting
name=value&gt;,在这个格式中,name的取值范围包含如下几个:<br />
locale:该选项指定该模板所用的国家/语言选项<br />
number_format:指定格式化输出数字的格式<br />
boolean_format:指定两个布尔值的语法格式,默认值是true,false<br />
date_format,time_format,datetime_format:指定格式化输出日期的格式<br />
time_zone:设置格式化输出日期时所使用的时区</p>
<p><strong><span style="font-size: small;">4.10 macro , nested ,
return指令</span></strong></p>
<p>macro可以用于实现自定义指令,通过使用自定义指令,可以将一段模板片段定义成一个用户指令,使用macro指令的语法格式如下:<br />
&lt;#macro
name param1 param2 ... paramN&gt;<br />
...<br />
&lt;#nested loopvar1, loopvar2, ...,
loopvarN&gt;<br />
...<br />
&lt;#return&gt;<br />
...<br />
&lt;/#macro&gt;<br />
在上面的格式片段中,包含了如下几个部分:<br />
name:name属性指定的是该自定义指令的名字,使用自定义指令时可以传入多个参数<br />
paramX:该属性就是指定使用自定义指令时报参数,使用该自定义指令时,必须为这些参数传入值<br />
nested指令:nested标签输出使用自定义指令时的中间部分<br />
nested指令中的循环变量:这此循环变量将由macro定义部分指定,传给使用标签的模板<br />
return指令:该指令可用于随时结束该自定义指令.</p>
<p>看如下的例子:<br />
&lt;#macro book&gt;&nbsp;&nbsp;
//定义一个自定义指令<br />
j2ee<br />
&lt;/#macro&gt;<br />
&lt;@book /&gt;&nbsp;&nbsp;&nbsp;
//使用刚才定义的指令<br />
上面的代码输出结果为:j2ee</p>
<p>在上面的代码中,可能很难看出自定义标签的用处,因为我们定义的book指令所包含的内容非常简单,实际上,自定义标签可包含非常多的内容,从而可以实现更好的代码复用.此外,还可以在定义自定义指令时,为自定义指令指定参数,看如下代码:<br />
&lt;#macro
book booklist&gt;&nbsp;&nbsp;&nbsp;&nbsp; //定义一个自定义指令booklist是参数<br />
&lt;#list booklist as
book&gt;<br />
&nbsp;&nbsp; ${book}<br />
&lt;/#list&gt;<br />
&lt;/#macro&gt;<br />
&lt;@book
booklist=["spring","j2ee"] /&gt;&nbsp;&nbsp;
//使用刚刚定义的指令<br />
上面的代码为book指令传入了一个参数值,上面的代码的输出结果为:spring j2ee</p>
<p>不仅如此,还可以在自定义指令时使用nested指令来输出自定义指令的中间部分,看如下例子:<br />
&lt;#macro page
title&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp;&nbsp; &lt;title&gt;FreeMarker示例页面 -
${title?html}&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp;&nbsp;
&lt;h1&gt;${title?html}&lt;/h1&gt;<br />
&nbsp;&nbsp; &lt;#nested&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
//用于引入用户自定义指令的标签体<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
&lt;/#macro&gt;<br />
上面的代码将一个HTML页面模板定义成一个page指令,则可以在其他页面中如此page指令:<br />
&lt;#import
"/common.ftl" as com&gt;&nbsp;&nbsp;&nbsp;&nbsp; //假设上面的模板页面名为common.ftl,导入页面<br />
&lt;@com.page
title="book
list"&gt;<br />
&lt;u1&gt;<br />
&lt;li&gt;spring&lt;/li&gt;<br />
&lt;li&gt;j2ee&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;<a>/@com.page</a>&gt;</p>
<p>从上面的例子可以看出,使用macro和nested指令可以非常容易地实现页面装饰效果,此外,还可以在使用nested指令时,指定一个或多个循环变量,看如下代码:<br />
&lt;#macro
book&gt;<br />
&lt;#nested 1&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用book指令时指定了一个循环变量值<br />
&lt;#nested
2&gt;<br />
&lt;/#macro&gt;<br />
&lt;@book ;x&gt; ${x}
.图书&lt;<a>/@book</a>&gt;<br />
当使用nested指令传入变量值时,在使用该自定义指令时,就需要使用一个占位符(如book指令后的;x).上面的代码输出文本如下:<br />
1
.图书&nbsp;&nbsp;&nbsp; 2 .图书</p>
<p>在nested指令中使用循环变量时,可以使用多个循环变量,看如下代码:<br />
&lt;#macro repeat
count&gt;<br />
&lt;#list 1..count as x&gt;&nbsp;&nbsp;&nbsp;&nbsp; //使用nested指令时指定了三个循环变量<br />
&nbsp;&nbsp;
&lt;#nested x, x/2,
x==count&gt;<br />
&lt;/#list&gt;<br />
&lt;/#macro&gt;<br />
&lt;@repeat count=4 ; c
halfc last&gt;<br />
${c}. ${halfc}&lt;#if last&gt; Last!
&lt;/#if&gt;<br />
&lt;<a>/@repeat</a>&gt;<br />
上面的输出结果为:<br />
1. 0.5&nbsp;&nbsp; 2. 1&nbsp;&nbsp; 3. 1.5&nbsp;&nbsp;
4. 2 Last;</p>
<p>return指令用于结束macro指令,一旦在macro指令中执行了return指令,则FreeMarker不会继续处理macro指令里的内容,看如下代码:<br />
&lt;#macro
book&gt;<br />
spring<br />
&lt;#return&gt;<br />
j2ee<br />
&lt;/#macro&gt;<br />
&lt;@book
/&gt;<br />
上面的代码输出:spring,而j2ee位于return指令之后,不会输出.</p>
</div>
<img src ="http://www.blogjava.net/jzone/aggbug/284300.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jzone/" target="_blank">Gavin.lee</a> 2009-06-26 15:59 <a href="http://www.blogjava.net/jzone/articles/284300.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>