??xml version="1.0" encoding="utf-8" standalone="yes"?>
截取字符串方法二Q?{str?substring(0,5)}
]]>
一直以来,都想在FTL模板面里应用java的方法?br />
“要想使用Freemarker支持的自定义ҎQ需要实现freemarker.template.TemplateMethodModel接口Q然后将Ҏ对象攑օ到Freemarker的数据模型中Q这样在ftl文g中便可以像用Freemarker内置Ҏ一样用该Ҏ了?#8221;
具体的需求方法:
package yixun.wap.tools;
import java.util.List;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModelException;
public class EncodeURLMethod implements TemplateMethodModel {
/**
* 执行Ҏ
* @param argList Ҏ参数列表
* @return Object Ҏq回?nbsp;
* @throws TemplateModelException
*/
public Object exec(List arg0) throws TemplateModelException {
if(arg0.size() != 1) { //限定Ҏ中必M只能传递一个参?/span>
throw new TemplateModelException("template exception");
}
String encode = java.net.URLEncoder.encode((String) arg0.get(0));
return encode;
}
}
EncodeURLMethod的实例对象放入模型中输出Q?br />
body.put("encodeURL", new EncodeURLMethod());
在Freemarker模版文g中应用:
${body.encodeURL("时时?/span>")}
得到的就是经qencoder的数据串了。这Lh非常方便了Q可以根据业务的需求,扩大FreeMarker的内|方法库?
]]>
2指o
if, else, elseif
switch, case, default, break
list, break
include
Import
compress
escape, noescape
assign
global
setting
macro, nested, return
t, lt, rt
3一些常用方法或注意事项
表达式{换类
数字循环
ҎQ点取整数
l变量默认?
判断对象是不是null
常用格式化日?
d全局׃n变量数据模型
直接调用java对象的方?
字符串处?内置Ҏ)
在模杉K对sequences和hashes初始?
注释标志
sequences内置Ҏ
hashes内置Ҏ
4 freemarker在web开发中注意事项
web中常用的几个对象
view中值的搜烦序
在模杉Kftl里用标{?
如何初始化共享变?
与webwork整合配置
5高Ҏ
自定义方?
自定?Transforms
1概念
最常用?个概?br />
sequence 序列Q对应java里的list、数l等非键值对的集?br />
hash 键值对的集?br />
namespace 对一个ftl文g的引?利用q个名字可以讉K到该ftl文g的资?/p>
2指o
if, else, elseif
语法
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
<#else>
...
</#if>
switch, case, default, break
语法
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
用例
字符?br />
<#switch being.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
数字
<#switch x>
<#case x = 1>
1
<#case x = 2>
2
<#default>
d
</#switch>
如果x=1 输出 1 2, x=2输出 2, x=3 输出d
list, break
语法
<#list sequence as item>
...
<#if item = "spring"><#break></#if>
...
</#list>
关键?br />
item_index:是list当前值的下标
item_has_next:判断list是否q有?/p>
用例
<#assign seq = ["winter", "spring", "summer", "autumn"]>
<#list seq as x>
${x_index + 1}. ${x}<#if x_has_next>,</#if>
</#list>
输出
1. winter,
2. spring,
3. summer,
4. autumn
include
语法
<#include filename>
or
<#include filename options>
options包含两个属?br />
encoding=”GBK” ~码格式
parse=true 是否作ؓftl语法解析,默认是trueQfalse是以文本方式引?注意在ftl文g里布值都是直接赋值的如parse=true,而不是parse=”true”
用例
/common/copyright.ftl包含内容
Copyright 2001-2002 ${me}<br>
All rights reserved.
模板文g
<#assign me = "Juila Smith">
<h1>Some test</h1>
<p>Yeah.
<hr>
<#include "/common/copyright.ftl" encoding=”GBK”>
输出l果
<h1>Some test</h1>
<p>Yeah.
<hr>
Copyright 2001-2002 Juila Smith
All rights reserved.
import
语法
<#import path as hash>
cM于java里的import,它导入文Ӟ然后可以在当前文g里用被导入文g里的宏组?/p>
用例
假设mylib.ftl里定义了宏copyright那么我们在其他模杉K面里可以q样使用
<#import "/libs/mylib.ftl" as my>
<@my.copyright date="1999-2002"/>
"my"在freemarker里被UCnamespace
compress
语法
<#compress>
...
</#compress>
用来压羃I白I间和空白的?br />
用例
<#assign x = " moo \n\n ">
(<#compress>
1 2 3 4 5
${moo}
test only
I said, test only
</#compress>)
输出
(1 2 3 4 5
moo
test only
I said, test only)
escape, noescape
语法
<#escape identifier as expression>
...
<#noescape>...</#noescape>
...
</#escape>
用例
主要使用在相似的字符串变量输出,比如某一个模块的所有字W串输出都必Lhtml安全的,q个时候就可以使用该表辑ּ
<#escape x as x?html>
First name: ${firstName}
<#noescape>Last name: ${lastName}</#noescape>
Maiden name: ${maidenName}
</#escape>
相同表达?
First name: ${firstName?html}
Last name: ${lastName }
Maiden name: ${maidenName?html}
assign
语法
<#assign name=value>
or
<#assign name1=value1 name2=value2 ... nameN=valueN>
or
<#assign same as above... in namespacehash>
or
<#assign name>
capture this
</#assign>
or
<#assign name in namespacehash>
capture this
</#assign>
用例
生成变量,q且l变量赋?br />
lseasons赋予序列?br />
<#assign seasons = ["winter", "spring", "summer", "autumn"]>
l变量test?
<#assign test = test + 1>
lmy namespage 赋予一个变量bgColor,下面可以通过my.bgColor来访问这个变?br />
<#import "/mylib.ftl" as my>
<#assign bgColor="red" in my>
一D输出的文本作ؓ变量保存在x?br />
下面的阴影部分输出的文本被赋值给x
<#assign x>
<#list 1..3 as n>
${n} <@myMacro />
</#list>
</#assign>
Number of words: ${x?word_list?size}
${x}
<#assign x>Hello ${user}!</#assign> error
<#assign x=” Hello ${user}!”> true
同时也支持中文赋|如:
<#assign 语法>
java
</#assign>
${语法}
打印输出:
java
global
语法
<#global name=value>
or
<#global name1=value1 name2=value2 ... nameN=valueN>
or
<#global name>
capture this
</#global>
全局赋D法,利用q个语法l变量赋|那么q个变量在所有的namespace中是可见?如果q个变量被当前的assign语法覆盖 ?lt;#global x=2> <#assign x=1> 在当前页面里x=2被隐藏Q或者通过${.global.x}来访?/p>
setting
语法
<#setting name=value>
用来讄整个pȝ的一个环?br />
locale
number_format
boolean_format
date_format, time_format, datetime_format
time_zone
classic_compatible
用例
假如当前是匈牙利的设|,然后修改成美?br />
${1.2}
<#setting locale="en_US">
${1.2}
输出
1,2
1.2
因ؓ匈牙利是采用“,”作ؓ十进制的分隔W,国是用“.”
macro, nested, return
语法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
用例
<#macro test foo bar="Bar" baaz=-1>
Test text, and the params: ${foo}, ${bar}, ${baaz}
</#macro>
<@test foo="a" bar="b" baaz=5*5-2/>
<@test foo="a" bar="b"/>
<@test foo="a" baaz=5*5-2/>
<@test foo="a"/>
输出
Test text, and the params: a, b, 23
Test text, and the params: a, b, -1
Test text, and the params: a, Bar, 23
Test text, and the params: a, Bar, -1
定义循环输出的宏
<#macro list title items>
<p>${title?cap_first}:
<ul>
<#list items as x>
<li>${x?cap_first}
</#list>
</ul>
</#macro>
<@list items=["mouse", "elephant", "python"] title="Animals"/>
输出l果
<p>Animals:
<ul>
<li>Mouse
<li>Elephant
<li>Python
</ul>
包含body的宏
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c halfc last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
输出
1. 0.5
2. 1
3. 1.5
4. 2 Last!
t, lt, rt
语法
<#t> L左右I白和回车换?/p>
<#lt>L左边I白和回车换?/p>
<#rt>L双I白和回车换?/p>
<#nt>取消上面的效?/p>
3一些常用方法或注意事项
表达式{换类
${expression}计算expressionq输?br />
#{ expression }数字计算#{ expression ;format}安格式输出数字format为M和m
M表示数点后最多的位数,m表示数点后最的位数?{121.2322;m2M2}输出121.23
数字循环
1..5 表示??Q原型number..number
ҎQ点取整数
${123.23?int} 输出123
l变量默认?br />
${var?default(“hello world<br>”)?html}如果var is null那么会被hello world<br>替代
判断对象是不是null
<#if mouse?exists>
Mouse found
<#else>
也可以直?{mouse?if_exists})输出布尔?br />
常用格式化日?br />
openingTime必须是Date?详细查看freemarker文档 Reference->build-in referece->build-in for date
${openingTime?date}
${openingTime?date_time}
${openingTime?time}
d全局׃n变量数据模型
在代码里的实?br />
cfg = Configuration.getDefaultConfiguration();
cfg.setSharedVariable("global", "you good");
面实现可以通过global指o,具体查看指o里的global部分
直接调用java对象的方?br />
${object.methed(args)}
字符串处?内置Ҏ)
html安全输出
“abc<table>sdfsf”?html
q回安全的html输出,替换掉html代码
xml安全输出
var?xml
substring的用?br />
<#assign user=”hello jeen”>
${user[0]}${user[4]}
${user[1..4]}
输出 :
ho
ello
cMString.split的用?br />
“abc;def;ghi”?split(“;”)q回sequence
字W串按空D{化成sequence,然后取sequence的长?br />
var?word_list 效果?var?split(“ ”)
var?word_list?size
取得字符串长?br />
var?length
大写输出字符
var?upper_case
写输出字符
var?lower_case
首字W大?br />
var?cap_first
首字W小?br />
var?uncap_first
L字符串前后空?br />
var?trim
每个单词的首字符大写
var?capitalize
cMString.indexof:
“babcdabcd”?index_of(“abc”) q回1
“babcdabcd”?index_of(“abc”,2) q回5
cMString.lastIndexOf
last_index_of和String.lastIndexOfcM,同上
下面两个可能在代码生成的时候用(在引号前?#8221;\”Q?br />
j_string: 在字W串引号前加”\”
<#assign beanName = 'The "foo" bean.'>
String BEAN_NAME = "${beanName?j_string}";
打印输出:
String BEAN_NAME = "The \"foo\" bean.";
js_string:
<#assign user = "Big Joe's \"right hand\".">
<script>
alert("Welcome ${user}!");
</script>
打印输出
alert("Welcome Big Joe\'s \"right hand\"!");
替换字符?replace
${s?replace('ba’, 'XY’ )}
${s?replace('ba’, 'XY’ , '规则参数’)}s里的所有的ba替换成xy 规则参数包含: i r m s c f 具体含义如下:
· i: 大小写不区分.
· f: 只替换第一个出现被替换字符串的字符?br />
· r: XY是正则表辑ּ
· 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.
· 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.
· c: Permits whitespace and comments in regular expressions.
在模杉K对sequences和hashes初始?br />
sequences
1. [“you”,”me”,”he”]
2. 1..100
3. [ {“Akey”:”Avalue”},{“Akey1”:”Avalue1”},
{“Bkey”:”Bvalue”},{“Bkey1”:”Bvalue1”},
]
hashes {“you”:”a”,”me”:”b”,”he”:”c”}
注释标志
<#--
q里是注?br />
-->
旧版本的freemarker采用的是<#comment> 注释 </#comment>Ҏ
sequences内置Ҏ
sequence?first
q回sequence的第一个?前提条gsequence不能是null
sequence?last
q回sequence最后一个?br />
sequence?reverse
反{sequence的?br />
sequence?size
q回sequence的大?br />
sequence?sort
对sequence按里面的对象toString()的结果进行排?br />
sequence?sort_by(value)
对sequence 按里面的对象的属性valueq行排序
? sequence里面攑օ的是10 个user对象Quser对象里面包含name,age{属?br />
sequence?sort_by(name) 表示所有的user按user.nameq行排序
hashes内置Ҏ
hash?keys
q回hash里的所有keys, q回l果cdsequence
hash?values
q回hash里的所有value, q回l果cdsequence
4 freemarker在web开发中注意事项
freemarker与webwork整合
web中常用的几个对象
Freemarker的ftl文g中直接用内部对?
${Request ["a"]}
${RequestParameters["a"]}
${Session ["a"]}
${Application ["a"]}
${JspTaglibs ["a"]}
与webwork整合之后 通过配置的servlet 已经把request,session{对象置入了数据模型?br />
在view中存在下面的对象
我们可以在ftl?{req}来打印req对象
· req - the current HttpServletRequest
· res - the current HttpServletResponse
· stack - the current OgnlValueStack
· ognl - the OgnlTool instance
· webwork - an instance of FreemarkerWebWorkUtil
· action - the current WebWork action
· exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
view中值的搜烦序
${name}会以下面的序查找name?br />
· freemarker variables
· value stack
· request attributes
· session attributes
· servlet context attributes
在模杉Kftl里用标{?br />
注意Q如果标{属性值是数字Q那么必采用nubmer=123方式l属性赋?br />
JSP面
<%@page contentType="text/html;charset=ISO-8859-2" language="java"%>
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<html>
<body>
<h1><bean:message key="welcome.title"/></h1>
<html:errors/>
<html:form action="/query">
Keyword: <html:text property="keyword"/><br>
Exclude: <html:text property="exclude"/><br>
<html:submit value="Send"/>
</html:form>
</body>
</html>
模板ftl面
<#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]>
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
<html>
<body>
<h1><@bean.message key="welcome.title"/></h1>
<@html.errors/>
<@html.form action="/query">
Keyword: <@html.text property="keyword"/><br>
Exclude: <@html.text property="exclude"/><br>
<@html.submit value="Send"/>
</@html.form>
</body>
</html>
如何初始化共享变?br />
1Q?初始化全局׃n数据模型
freemark在web上用的时候对׃n数据的初始化支持的不?不能在配|初始化的时候实玎ͼ而必通过ftl文g来初始化全局变量。这是不能满主需求的Q我们需要在servlet init的时候留Z个接口来初始化系l的׃n数据
具体到和webwork整合,因ؓ本nwebwork提供了整合servlet,如果要增加全局׃n变量Q可以通过修改 com.opensymphony.webwork.views.freemarker.FreemarkerServlet来实?我们可以在这?servlet初始化的时候来初始化全局׃n变量
与webwork整合配置
配置web.xml
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>com.opensymphony.webwork.views.freemarker.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
<!—模板蝲入文件夹Q这里相对context rootQ递归获取该文件夹下的所有模?->
</init-param>
<init-param>
<param-name>NoCache</param-name> <!—是否对模板~存-->
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>ContentType</param-name>
<param-value>text/html</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<!—模板更新时?0表示每次都更?q个适合开发时?->
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value><!—数字显C格?->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
5高Ҏ
自定义方?br />
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
在模板中除了可以通过对象来调用方法外Q?{object.methed(args)}Q也可以直接调用java实现的方法,javacdd现接口TemplateMethodModel的方法exec(List args). 下面以把毫秒的时间{换成按格式输出的旉Z?br />
public class LongToDate implements TemplateMethodModel {
public TemplateModel exec(List args) throws TemplateModelException {
SimpleDateFormat mydate = new SimpleDateFormat((String) args.get(0)));
return mydate.format(new Date(Long.parseLong((String)args.get(1)));
}
}
LongToDate对象攑օ到数据模型中
root.put("timer", new IndexOfMethod());
ftl模板里?br />
<#assign x = "123112455445">
${timer("yyyy-MM-dd H:mm:ss", x)}
${timer("yyyy-MM-dd ", x)}
输出
2001-10-12 5:21:12
2001-10-12
自定?Transforms
实现自定义的<@transform>文本或表辑ּ</@transform>的功?允许对中间的最l文本进行解析{?/p>
例子Q实?lt;@upcase>str</@upcase> str转换成STR 的功?/p>
代码如下Q?br />
import java.io.*;
import java.util.*;
import freemarker.template.TemplateTransformModel;
class UpperCaseTransform implements TemplateTransformModel {
public Writer getWriter(Writer out, Map args) {
return new UpperCaseWriter(out);
}
private class UpperCaseWriter extends Writer {
private Writer out;
UpperCaseWriter (Writer out) {
this.out = out;
}
public void write(char[] cbuf, int off, int len)
throws IOException {
out.write(new String(cbuf, off, len).toUpperCase());
}
public void flush() throws IOException {
out.flush();
}
public void close() {
}
}
}
然后此对象put到数据模型中
root.put("upcase", new UpperCaseTransform());
在view(ftl)面中可以如下方式?/p>
<@upcase>
hello world
</@upcase>
打印输出:
HELLO WORLD
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)
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)
注:
׃freemarker强烈不支持nullQ所以这个问题呢Q多半就是JSPQ或抛数据源的地方)数据没有正确的传q来。究其原因,不在ftl模板? MyEclipse控制台输出:一看知道哪个页面,哪行错了Qso easy…? O(∩_?O~
[09:44:50.546] Compiling _jsp/_page/_news/_prize/_open/_ssc__jsp.java
[ERROR]
Expression s.expect is undefined on line 7, column 11 in news/prize/open/ssc.ftl.
The problematic instruction:
----------
==> ${s.expect} [on line 7, column 9 in news/prize/open/ssc.ftl]
in user-directive f.page [on line 3, column 1 in news/prize/open/ssc.ftl]
----------
Java backtrace for programmers:
----------
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)
…?br />…?/pre>
]]>
http://freemarker.org/docs/index.html 官方手册
FreeMarker的模板文件ƈ不比HTML面复杂多少,FreeMarker模板文g主要由如?个部分组?
1,文本:直接输出的部?br />
2,注释:<#--
...
-->格式部分,不会输出
3,插??{...}?{...}格式的部?用数据模型中的部分替代输?br />
4,FTL指o:FreeMarker指定,和HTML标记cM,名字前加#予以区分,不会输出
下面是一个FreeMarker模板的例?包含了以上所说的4个部?br />
<html><br>
<head><br>
<title>Welcome!</title><br>
</head><br>
<body><br>
<#--
注释部分 --><br>
<#-- 下面使用插?-->
<h1>Welcome ${user}
!</h1><br>
<p>We have these
animals:<br>
<u1><br>
<#-- 使用FTL指o
-->
<#list animals as being><br>
<li>${being.name}
for ${being.price}
Euros<br>
<#list><br>
<u1><br>
</body><br>
</html>
1, FTL指o规则
在FreeMarker?使用FTL标签来用指?FreeMarker?UFTL标签,q和HTML标签是完全类似的.
1,开始标{?<#directivename
parameter>
2,l束标签:</#directivename>
3,I标{?<#directivename
parameter/>
实际?使用标签时前面的W号#也可能变成@,如果该指令是一个用h令而不是系l内建指令时,应将#W号Ҏ@W号.
使用FTL标签?应该有正的嵌套,而不是交叉?q和XML标签的用法完全一?如果全用不存在的指o,FreeMarker不会使用模板输出,而是产生一个错误消?FreeMarker会忽略FTL标签中的I白字符.值得注意的是<
, /> 和指令之间不允许有空白字W?
2, 插D?/span>
FreeMarker的插值有如下两种cd:1,通用插?{expr};2,数字格式化插?#{expr}?{expr;format}
2.1 通用插?/span>
对于通用插?又可以分Z?U情?
1,插值结果ؓ字符串?直接输出表达式结?br />
2,插值结果ؓ数字?Ҏ默认格式(?setting指o讄)表辑ּl果转换成文本输?可以使用内徏的字W串函数格式化单个插?如下面的例子:
<#settion
number_format="currency"/>
<#assign
answer=42/>
${answer}
${answer?string} <#-- the same as ${answer}
-->
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
${answer}
输出l果?
$42.00
$42.00
42
$42.00
4,200%
3,插值结果ؓ日期?Ҏ默认格式(?setting指o讄)表辑ּl果转换成文本输?可以使用内徏的字W串函数格式化单个插?如下面的例子:
${lastUpdated?string("yyyy-MM-dd
HH:mm:ss zzzz")}
${lastUpdated?string("EEE, MMM d,
''yy")}
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a
'('zzz')'")}
输出l果?
2008-04-08 08:08:08 Pacific Daylight Time
Tue, Apr
8, '03
Tuesday, April 08, 2003, 08:08:08 PM
(PDT)
4,插值结果ؓ布尔?Ҏ默认格式(?setting指o讄)表辑ּl果转换成文本输?可以使用内徏的字W串函数格式化单个插?如下面的例子:
<#assign
foo=true/>
${foo?string("yes", "no")}
输出l果?
yes
2.2 数字格式化插?/span>
数字格式化插值可采用#{expr;format}形式来格式化数字,其中format可以?
mX:数部分最X?br />
MX:数部分最大X?br />
如下面的例子:
<#assign
x=2.582/>
<#assign y=4/>
#{x; M2} <#-- 输出2.58 -->
#{y;
M2} <#-- 输出4 -->
#{x; m2} <#-- 输出2.6 -->
#{y; m2} <#--
输出4.0 -->
#{x; m1M2} <#-- 输出2.58 -->
#{x; m1M2} <#-- 输出4.0
-->
3, 表达?/span>
表达式是FreeMarker模板的核心功?表达式放|在插D?{}之中?表明需要输辑ּ的?表达式语法也可与FreeMarker标签l合,用于控制输出.实际上FreeMarker的表辑ּ功能非常强大,它不仅支持直接指定?输出变量?也支持字W串格式化输出和集合讉K{功?
3.1 直接指定?/span>
使用直接指定D法让FreeMarker直接输出插g的?而不是输出变量?直接指定值可以是字符?数?布尔?集合和MAP对象.
1,字符?br />
直接指定字符串g用单引号或双引号限定,如果字符串g包含Ҏ字符需要{?看下面的例子:
${"我的文g保存在C:\\?}
${'我名字是\"annlee\"'}
输出l果?
我的文g保存在C:\?br />
我名字是"annlee"
FreeMarker支持如下转义字符:
\";双引?u0022)
\';单引?u0027)
\\;反斜?u005C)
\n;换行(u000A)
\r;回R(u000D)
\t;Tab(u0009)
\b;退格键(u0008)
\f;Form
feed(u000C)
\l;<
\g;>
\a;&
\{;{
\xCode;直接通过4位的16q制数来指定Unicode?输出该unicode码对应的字符.
如果某段文本中包含大量的ҎW号,FreeMarker提供了另一U特D格?可以在指定字W串内容的引号前增加r标记,在r标记后的文g会直接输出.看如下代?
${r"${foo}"}
${r"C:\foo\bar"}
输出l果?
${foo}
C:\foo\bar
2,数?br />
表达式中的数值直接输?不需要引?数点?."分隔,不能使用分组","W号.FreeMarker目前q不支持U学计数?所?1E3"是错误的.在FreeMarker表达式中使用数值需要注意以下几?
1,数g能省略小数点前面?,所?.5"是错误的写法
2,数?
, +8 , 8.00都是相同?/p>
3,布尔?br /> 直接使用true和false,不用引?
4,集合
集合以方括号包括,各集合元素之间以英文逗号","分隔,看如下的例子:
<#list ["星期一", "星期?, "星期?,
"星期?, "星期?, "星期?, "星期?] as
x>
${x}
</#list>
输出l果?
星期一
星期?br />
星期?br />
星期?br />
星期?br />
星期?br />
星期?/p>
除此之外,集合元素也可以是表达?例子如下:
[2 + 2, [1, 2, 3, 4], "whatnot"]
q可以用数字范围定义数字集??..5{同于[2, 3, 4, 5],但是更有效率.注意,使用数字范围来定义集合时无需使用Ҏ?数字范围也支持反递增的数字范??..2
5,Map对象
Map对象使用花括号包?Map中的key-value对之间以英文冒号":"分隔,多组key-value对之间以英文逗号","分隔.下面是一个例?
{"语文":78,
"数学":80}
Map对象的key和value都是表达?但是key必须是字W串
3.2 输出变量?/span>
FreeMarker的表辑ּ输出变量?q些变量可以是顶层变?也可以是Map对象中的变量,q可以是集合中的变量,q可以用点(.)语法来访问Java对象的属?下面分别讨论q些情况
1,层变量
所谓顶层变量就是直接放在数据模型中的?例如有如下数据模?
Map root = new HashMap();
//创徏数据模型
root.put("name","annlee"); //name是一个顶层变?/p>
对于层变量,直接使用${variableName}来输出变量?变量名只能是字母,数字,下划U?$,@?的组?且不能以数字开头号.Z输出上面的name的?可以使用如下语法:
${name}
2,输出集合元素
如果需要输出集合元?则可以根据集合元素的索引来输出集合元?集合元素的烦引以Ҏh?假设有烦?
["星期一","星期?,"星期?,"星期?,"星期?,"星期?,"星期?].该烦引名为week,如果需要输出星期三,则可以用如下语?
${week[2]}
//输出W三个集合元?/p>
此外,FreeMarkerq支持返回集合的子集?如果需要返回集合的子集?则可以用如下语?
week[3..5]
//q回week集合的子集合,子集合中的元素是week集合中的W?-6个元?/p>
3,输出Map元素
q里的Map对象可以是直接HashMap的实?甚至包括JavaBean实例,对于JavaBean实例而言,我们一样可以把其当成属性ؓkey,属性gؓvalue的Map实例.Z输出Map元素的?可以使用点语法或Ҏ可?假如有下面的数据模型:
Map
root = new HashMap();
Book book = new Book();
Author author = new
Author();
author.setName("annlee");
author.setAddress("gz");
book.setName("struts2");
book.setAuthor(author);
root.put("info","struts");
root.put("book",
book);
Z讉K数据模型中名为struts2的书的作者的名字,可以使用如下语法:
book.author.name
//全部使用点语?br />
book["author"].name
book.author["name"]
//混合使用点语法和Ҏ可?br />
book["author"]["name"] //全部使用Ҏ可?/p>
使用点语法时,变量名字有顶层变量一L限制,但方括号语法没有该限?因ؓ名字可以是Q意表辑ּ的结?
3.3, 字符串操?/span>
FreeMarker的表辑ּ对字W串操作非常灉|,可以字W串帔R和变量连接v?也可以返回字W串的子串等.
字符串连接有两种语法:
1,使用${..}?{..}在字W串帔R部分插入表达式的?从而完成字W串q接.
2,直接使用q接q算W?来连接字W串
例如有如下数据模?
Map root = new HashMap();
root.put("user","annlee");
下面user变量和常量连接v?
${"hello, ${user}!"}
//使用W一U语法来q接
${"hello, " + user + "!"}
//使用+hq接
上面的输出字W串都是hello,annlee!,可以看出q两U语法的效果完全一?
值得注意的是,${..}只能用于文本部分,不能用于表达?下面的代码是错误?
<#if
${isBig}>Wow!</#if>
<#if
"${isBig}">Wow!</#if>
应该写成:<#if isBig>Wow!</#if>
截取子串可以Ҏ字符串的索引来进?截取子串时如果只指定了一个烦引?则用于取得字W串中指定烦引所对应的字W?如果指定两个索引?则返回两个烦引中间的字符串子?假如有如下数据模?
Map
root = new HashMap();
root.put("book","struts2,freemarker");
可以通过如下语法来截取子?
${book[0]}${book[4]}
//l果是su
${book[1..4]} //l果是tru
3.4 集合q接q算W?/span>
q里所说的集合q算W是两个集合连接成一个新的集?q接集合的运符?,看如下的例子:
<#list ["星期一","星期?,"星期?]
+ ["星期?,"星期?,"星期?,"星期?] as x>
${x}
</#list>
输出l果?星期一 星期?
星期?星期?星期?星期?星期?/p>
3.5 Mapq接q算W?/span>
Map对象的连接运符也是两个Map对象q接成一个新的Map对象,Map对象的连接运符?,如果两个Map对象h相同的key,则右边的值替代左边的?看如下的例子:
<#assign
scores = {"语文":86,"数学":78} +
{"数学":87,"Java":93}>
语文成W?{scores.语文}
数学成W?{scores.数学}
Java成W?{scores.Java}
输出l果?
语文成W?6
数学成W?7
Java成W?3
3.6 术q算W?/span>
FreeMarker表达式中完全支持术q算,FreeMarker支持的算术运符包括:+, - , * , / , %
看如下的代码:
<#assign x=5>
${ x * x - 100 }
${ x /2 }
${ 12 %10
}
输出l果?
-75 2.5 2
在表辑ּ中用算术运符时要注意以下几点:
1,q算W两边的q算数字必须是数?br />
2,使用+q算W时,如果一Ҏ数字,一Ҏ字符?׃自动数字{换ؓ字符串再q接,?${3
+ "5"},l果?35
使用内徏的int函数可对数值取??
<#assign x=5>
${ (x/2)?int }
${ 1.1?int
}
${ 1.999?int }
${ -1.1?int }
${ -1.999?int }
l果?2 1 1 -1 -1
3.7 比较q算W?/span>
表达式中支持的比较运符有如下几?
1,=或?=:判断两个值是否相{?
2,!=:判断两个值是否不{?
3,>或者gt:判断左边值是否大于右边?br />
4,>=或者gte:判断左边值是否大于等于右边?br />
5,<或者lt:判断左边值是否小于右边?br />
6,<=或者lte:判断左边值是否小于等于右边?/p>
注意:=?=可以用于字符?数值和日期来比较是否相{???=两边必须是相同类型的?否则会生错?而且FreeMarker是精比?"x","x ","X"是不{的.其它的运行符可以作用于数字和日期,但不能作用于字符?大部分的时?使用gt{字母运符代替>会有更好的效?因ؓFreeMarker会把>解释成FTL标签的结束字W?当然,也可以用括h避免q种情况,?<#if (x>y)>
3.8 逻辑q算W?/span>
逻辑q算W有如下几个:
逻辑?&&
逻辑?||
逻辑?!
逻辑q算W只能作用于布尔?否则生错?/p>
3.9 内徏函数
FreeMarkerq提供了一些内建函数来转换输出,可以在Q何变量后紧跟?,?后紧跟内建函?可以通过内徏函数来轮换输出变?下面是常用的内徏的字W串函数:
html:对字W串q行HTML~码
cap_first:使字W串W一个字母大?br />
lower_case:字W串转换成小?br />
upper_case:字W串转换成大?br />
trim:L字符串前后的I白字符
下面是集合的常用内徏函数
size:获取序列中元素的个数
下面是数字值的常用内徏函数
int:取得数字的整数部?l果带符?/p>
例如:
<#assign test="Tom &
Jerry">
${test?html}
${test?upper_case?html}
l果?Tom &
Jerry TOM & JERRY
3.10 I值处理运符
FreeMarker对空值的处理非常严格,FreeMarker的变量必L?没有被赋值的变量׃抛出异常,因ؓFreeMarker未赋值的变量强制出错可以杜绝很多潜在的错?如缺失潜在的变量命名,或者其他变量错?q里所说的I?实际上也包括那些q不存在的变?对于一个Java的nullD言,我们认ؓq个变量是存在的,只是它的gؓnull,但对于FreeMarker模板而言,它无法理解null?null值和不存在的变量完全相同.
Z处理~失变量,FreeMarker提供了两个运符:
!:指定~失变量的默认?br />
??:判断某个变量是否存在
其中,!q算W的用法有如下两U?
variable!或variable!defaultValue,W一U用法不l缺q变量指定默认?表明默认值是I字W串,长度?的集?或者长度ؓ0的Map对象.
使用!指定默认值时,q不要求默认值的cd和变量类型相?使用??q算W非常简?它Lq回一个布?用法?variable??,如果该变量存?q回true,否则q回false
3.11 q算W的优先U?/span>
FreeMarker中的q算W优先如下(由高C排列):
1,一元运符:!
2,内徏函数:?
3,乘除?*, / ,
%
4,加减?- , +
5,比较:> , < , >= , <= (lt , lte , gt ,
gte)
6,相等:== , = , !=
7,逻辑?&&
8,逻辑?||
9,数字范围:..
实际?我们在开发过E中应该使用括号来严格区?q样的可L好,出错?/p>
4 FreeMarker的常用指?/span>
FreeMarker的FTL指o也是模板的重要组成部?q些指o可实现对数据模型所包含数据的抚今P?分支控制.除此之外,q有一些重要的功能,也是通过FTL指o来实现的.
4.1 if指o
q是一个典型的分支控制指o,该指令的作用完全cM于Java语言中的if,if指o的语法格式如?
<#if
condition>...
<#elseif condition>...
<#elseif
condition>...
<#else> ...
</#if>
例子如下:
<#assign age=23>
<#if (age>60)>老年?br />
<#elseif
(age>40)>中年?br />
<#elseif (age>20)>青年?br />
<#else>
年?br />
</#if>
输出l果?青年?br />
上面的代码中的逻辑表达式用括号括v来主要是因ؓ里面?gt;W号,׃FreeMarker会将>W号当成标签的结束字W?可能DE序出错,Z避免q种情况,我们应该在凡是出现这些符L地方都用括?
4.2 switch , case , default , break指o
q些指o昄是分支指?作用cM于Java的switch语句,switch指o的语法结构如?
<#switch
value>
<#case refValue>...<#break>
<#case
refValue>...<#break>
<#default>...
</#switch>
4.3 list, break指o
list指o是一个P代输出指?用于q代输出数据模型中的集合,list指o的语法格式如?
<#list sequence as
item>
...
</#list>
上面的语法格式中,sequence是一个集合对?也可以是一个表辑ּ,但该表达式将q回一个集合对?而item是一个Q意的名字,是被P代输出的集合元素.此外,q代集合对象?q包含两个特D的循环变量:
item_index:当前变量的烦引?br />
item_has_next:是否存在下一个对?br />
也可以?lt;#break>指o跛_q代
例子如下:
<#list ["星期一", "星期?, "星期?, "星期?, "星期?, "星期?, "星期?] as
x>
${x_index + 1}.${x}<#if x_has_next>,</if>
<#if
x="星期?><#break></#if>
</#list>
4.4 include指o
include指o的作用类gJSP的包含指?用于包含指定?include指o的语法格式如?
<#include filename
[options]>
在上面的语法格式?两个参数的解释如?
filename:该参数指定被包含的模板文?br />
options:该参数可以省?指定包含时的选项,包含encoding和parse两个选项,其中encoding指定包含面时所用的解码?而parse指定被包含文件是否作为FTL文g来解?如果省略了parse选项?则该选项默认是true.
4.5 import指o
该指令用于导入FreeMarker模板中的所有变?q将该变量放|在指定的Map对象?import指o的语法格式如?
<#import
"/lib/common.ftl" as
com>
上面的代码将导入/lib/common.ftl模板文g中的所有变?交将q些变量攄在一个名为com的Map对象?
4.6 noparse指o
noparse指o指定FreeMarker不处理该指定里包含的内容,该指令的语法格式如下:
<#noparse>...</#noparse>
看如下的例子:
<#noparse>
<#list books as book>
<tr><td>${book.name}<td>作?${book.author}
</#list>
</#noparse>
输出如下:
<#list
books as book>
<tr><td>${book.name}<td>作?${book.author}
</#list>
4.7 escape , noescape指o
escape指oDbody区的插值都会被自动加上escape表达?但不会媄响字W串内的插?只会影响到body内出现的插?使用escape指o的语法格式如?
<#escape
identifier as
expression>...
<#noescape>...</#noescape>
</#escape>
看如下的代码:
<#escape x as x?html>
First name:${firstName}
Last
name:${lastName}
Maiden
name:${maidenName}
</#escape>
上面的代码等同于:
First
name:${firstName?html}
Last name:${lastName?html}
Maiden
name:${maidenName?html}
escape指o在解析模板时起作用而不是在q行时v作用,除此之外,escape指o也嵌套?子escapel承父escape的规?如下例子:
<#escape
x as x?html>
Customer Name:${customerName}
Items to
ship;
<#escape x as itemCodeToNameMap[x]>
${itemCode1}
${itemCode2}
${itemCode3}
${itemCode4}
</#escape>
</#escape>
上面的代码类g:
Customer
Name:${customerName?html}
Items to
ship;
${itemCodeToNameMap[itemCode1]?html}
${itemCodeToNameMap[itemCode2]?html}
${itemCodeToNameMap[itemCode3]?html}
${itemCodeToNameMap[itemCode4]?html}
对于攑֜escape指o中所有的插D言,q此插值将被自动加上escape表达?如果需要指定escape指o中某些插值无需descape表达?则应该用noescape指o,攑֜noescape指o中的插值将不会descape表达?
4.8 assign指o
assign指o在前面已l用了多次,它用于ؓ该模杉K面创建或替换一个顶层变?assign指o的用法有多种,包含创徏或替换一个顶层变?或者创建或替换多个变量{?它的最单的语法如下:<#assign name=value [in namespacehash]>,q个用法用于指定一个名为name的变?该变量的gؓvalue,此外,FreeMarker允许在用assign指o里增加in子句,in子句用于创建的name变量攑օnamespacehash命名I间?
assign指oq有如下用法:<#assign name1=value1 name2=value2 ... nameN=valueN [in
namespacehash]>,q个语法可以同时创徏或替换多个顶层变?此外,q有一U复杂的用法,如果需要创建或替换的变量值是一个复杂的表达?则可以用如下语法格?<#assign
name [in namespacehash]>capture
this</#assign>,在这个语法中,是指assign指o的内容赋值给name变量.如下例子:
<#assign
x>
<#list ["星期一", "星期?, "星期?, "星期?, "星期?, "星期?, "星期?] as
n>
${n}
</#list>
</#assign>
${x}
上面的代码将产生如下输出:星期一
星期?星期?星期?星期?星期?星期?/p>
虽然assign指定了这U复杂变量值的用法,但是我们也不要滥用这U用?如下例子:<#assign x>Hello ${user}!</#assign>,以上代码改ؓ如下写法更合?<#assign x="Hello ${user}!">
4.9 setting指o
该指令用于设|FreeMarker的运行环?该指令的语法格式如下:<#setting
name=value>,在这个格式中,name的取D围包含如下几?
locale:该选项指定该模板所用的国家/语言选项
number_format:指定格式化输出数字的格式
boolean_format:指定两个布尔值的语法格式,默认值是true,false
date_format,time_format,datetime_format:指定格式化输出日期的格式
time_zone:讄格式化输出日期时所使用的时?/p>
4.10 macro , nested , return指o
macro可以用于实现自定义指?通过使用自定义指?可以一D|板片D定义成一个用h?使用macro指o的语法格式如?
<#macro
name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ...,
loopvarN>
...
<#return>
...
</#macro>
在上面的格式片段?包含了如下几个部?
name:name属性指定的是该自定义指令的名字,使用自定义指令时可以传入多个参数
paramX:该属性就是指定用自定义指o时报参数,使用该自定义指o?必须些参C入?br />
nested指o:nested标签输出使用自定义指令时的中间部?br />
nested指o中的循环变量:q此循环变量由macro定义部分指定,传给使用标签的模?br />
return指o:该指令可用于随时l束该自定义指o.
看如下的例子:
<#macro book>
//定义一个自定义指o
j2ee
</#macro>
<@book />
//使用刚才定义的指?br />
上面的代码输出结果ؓ:j2ee
在上面的代码?可能很难看出自定义标{用处,因ؓ我们定义的book指o所包含的内定w常简?实际?自定义标{֏包含非常多的内容,从而可以实现更好的代码复用.此外,q可以在定义自定义指令时,定义指o指定参数,看如下代?
<#macro
book booklist> //定义一个自定义指obooklist是参?br />
<#list booklist as
book>
${book}
</#list>
</#macro>
<@book
booklist=["spring","j2ee"] />
//使用刚刚定义的指?br />
上面的代码ؓbook指o传入了一个参数?上面的代码的输出l果?spring j2ee
不仅如此,q可以在自定义指令时使用nested指o来输定义指o的中间部?看如下例?
<#macro page
title>
<html>
<head>
<title>FreeMarkerCZ面 -
${title?html}</title>
</head>
<body>
<h1>${title?html}</h1>
<#nested>
//用于引入用户自定义指令的标签?br />
</body>
</html>
</#macro>
上面的代码将一个HTML面模板定义成一个page指o,则可以在其他面中如此page指o:
<#import
"/common.ftl" as com> //假设上面的模杉K面名为common.ftl,导入面
<@com.page
title="book
list">
<u1>
<li>spring</li>
<li>j2ee</li>
</ul>
</@com.page>
从上面的例子可以看出,使用macro和nested指o可以非常Ҏ地实现页面装饰效?此外,q可以在使用nested指o?指定一个或多个循环变量,看如下代?
<#macro
book>
<#nested 1> //使用book指o时指定了一个@环变量?br />
<#nested
2>
</#macro>
<@book ;x> ${x}
.图书</@book>
当用nested指o传入变量值时,在用该自定义指令时,需要用一个占位符(如book指o后的;x).上面的代码输出文本如?
1
.图书 2 .图书
在nested指o中用@环变量时,可以使用多个循环变量,看如下代?
<#macro repeat
count>
<#list 1..count as x> //使用nested指o时指定了三个循环变量
<#nested x, x/2,
x==count>
</#list>
</#macro>
<@repeat count=4 ; c
halfc last>
${c}. ${halfc}<#if last> Last!
</#if>
</@repeat>
上面的输出结果ؓ:
1. 0.5 2. 1 3. 1.5
4. 2 Last;
return指o用于l束macro指o,一旦在macro指o中执行了return指o,则FreeMarker不会l箋处理macro指o里的内容,看如下代?
<#macro
book>
spring
<#return>
j2ee
</#macro>
<@book
/>
上面的代码输?spring,而j2ee位于return指o之后,不会输出.