??xml version="1.0" encoding="utf-8" standalone="yes"?>
二.环境搭徏与配|?/strong>
三.常用语法
四.与Strutsl合
五.生成Html面
一QFreemarker?br />
什么是Freemarker:.
Freemaker是一个”模板引擎?也可以说是一个基于模板技术的生成文本输出的一个通用工具.它是一个JAVA的包,一个JAVAE序员可以用的
cd.本nq不是一个对最l用L(fng)应用E序.但是,E序员可以把它应用到他们的品中.
FreeMarker是设计ؓ(f)可以生成WEB PAGES.它是ZSERVLET遵@MVC模式?q个思\是应用MVC模式要降低分?|页设计人员和程序员的耦合.
每个人都可以做他们擅长的工作.|页设计人员可以改变|页的面?而ƈ不需要程序员的重新编?因ؓ(f)业务逻辑和页面的设计已经被分d?/p>
.模板是不能由复杂的程序片断组成的.即便|页设计人员和程序员是一个h. 分离是有必要?它能使程序更加的灉|和清?
虽然Freemarker能编E?但是它ƈ不是一个编E语a.它是为程序显C数据而准备的.(像数据库SQL语句的查?)以及(qing).Freemarker仅仅是利用模
板加上数据生成文本页?
Freemarkerq不是一个WEB应用E序框架.可以说是一个WEB应用框架的一个组?但是FREEMARKER引擎本nq不了解HTTP或者SERVLETS.它只不过
生成文本而已.注意,它是MVC框架的一个组?如STRUTS),也可以在模板中用JSP标签.
Freemarker下蝲地址为:(x)http://www.freemarker.org/index.html
一般的用?
l 能用来生成Q意格式的文本:HTML,XML,RTF,JAVA源码,{等.
l可以更好的嵌入到你的产品?轻量U的.q不需要servlet环境.不依赖javax.servlet.classes.
l可插入的模板d?你可以从L的源码读取Q意的模板.本地的文?数据库等{?
l你可以做L你想生成的文?存储为本地文?可以用来发送EMAIL或返回到WEB览器中.
强大的模板语a
l完整的指?include,if/elseif/else,loop.
l 建立和修Ҏ(gu)板中的变?
l 能用复杂的表辑ּ在Q意地Ҏ(gu)定变?
n字符串操?concateration,sub-string,uppercase,capitalize,escaping.{等
n十进制数学计?
n BOOL
nd数组和相关的数组元素.
n可以自己dҎ(gu)的计方?
l宏指?/p>
l 命名I间用来创徏和维护宏指o(h)库或者把大的目分成许多模块.q不用担心命名冲H?br />
----------------------------------------------------------------------------
二.环境搭徏与配|?br />
<!—freemarker初始配置-->
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</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>
<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>locale</param-name>
<param-value>zh_CN </param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
----------------------------------------------------------------------------
三.常用语法
EG.一个对象BOOK
1.输出 ${book.name}
I值判断:(x)${book.name?if_exists },
${book.name?default(‘xxx?}//默认值xxx
${ book.name!"xxx"}//默认值xxx
日期格式Q?{book.date?string('yyyy-MM-dd')}
数字格式Q?{book?string.number}--20
${book?string.currency}--<#-- $20.00 -->
${book?string.percent}?lt;#-- 20% -->
插入布尔|(x)
<#assign foo=ture />
${foo?string("yes","no")} <#-- yes -->
2Q逻辑判断
a:
<#if condition>...
<#elseif condition2>...
<#elseif condition3>......
<#else>...
其中I值判断可以写?lt;#if book.name?? >
</#if>
b:
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
</#switch>
3Q@环读?br /><#list sequence as item>
...
</#list>
I值判?lt;#if bookList?size = 0></#list>
e.g.
<#list employees as e>
${e_index}. ${e.name}
</#list>
输出:
1. Readonly
2. Robbin
4.FreeMarker
4 ?模板
宏Macro
宏是在模板中使用macro指o(h)定义
l.1 基本用法
宏是和某个变量关联的模板片断Q以便在模板中通过用户定义指o(h)使用该变量,下面是一个例子:(x)
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
调用宏时Q与使用FreeMarker的其他指令类|
只是使用@替代FTL标记中的#?/strong>
<@greet></@greet>
<#--<@greet/>-->
<#macro greet person>
可以q样使用该宏变量Q其中参数的ơ序是无关的Q?br /><@greet person="Fred" color="black"/> 可以在定义参数时指定~省|否则Q在调用宏的时候,必须Ҏ(gu)有参数赋|(x) 注意Q宏的参数是局部变量,只能在宏定义中有效?/p>
<#macro border> 执行宏调用:(x) <#nested>指o(h)可以被多ơ调用,每次都会(x)执行相同的内宏V?br /><#macro do_thrice>
FMPP 输出l果Q?br />Anything. 嵌套内容可以是有效的FTLQ下面是一个有些复杂的例子Q我们将上面三个宏组合v来:(x)
宏定义中的局部变量对嵌套内容是不可见?/strong>Q例如:(x) <@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat> 输出l果Q?br />test 3/1: ? ? ?
<@ macro_name paramter list; loop variable list[,]> 例如Q?br /><#macro repeat count> <@repeat count=4 ; c, halfc, last> q里count是宏的参敎ͼc, halfc,last则ؓ(f)循环变量Q输出结果:(x) 不会(x)被创建:(x) <@repeat count=4 ; c, halfc> <@repeat count=4>
在模板中定义变量 <#assign x = "plain"> <@test/> 模型中的user的值是Big JoeQ?br /><#assign user = "Joe Hider"> 其目的是防止同名冲突 Q下面是一个例子:(x)
1.输出文g换成以ftl格式的文?/p>
E.G. <action name="bookActionForm" parameter="method" path="/bookAction" scope="request" type="example.BookAction" validate="true"> <forward name="list" path="/index.ftl"/> </action> 2.使用strutsQjstl{标{?/p>
a.导入à<#global html=JspTaglibs["/WEB-INF/tags/struts-html.tld"]> ?lt;#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]> b.使用à<@bean.page id="request" property="request"/>,
----------------------------------------------------------------------------
例子QMakeFileManager.java package example; import freemarker.template.Configuration; public class MakeFileManager { String realPath = bookFtl.getRealPath();
在macro指o(h)中可以在宏变量之后定义参?/strong>Q如Q?/p>
<font size="+2">Hello ${person}!</font>
</#macro>
可以q样使用q个宏变量:(x)
<@greet person="Fred"/>
但是下面的代码具有不同的意思:(x)
<@greet person=Fred/>
q意味着Fred变量的glperson参数Q该g仅是字符Ԍq可以是其它cdQ甚x复杂的表辑ּ?/p>
宏可以有多参敎ͼ下面是一个例?/strong>Q?br /><#macro greet person color>
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
<#macro greet person color="black">
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
在宏里嵌套内?br />FreeMarker的宏可以有嵌套内容,
<#nested>指o(h)?x)执行宏调用指o(h)开始和l束标记之间的模板片断,举一个简单的例子Q?/p>
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</tr></td></table>
</#macro>
<@border>The bordered text</@border>
输出l果Q?br /><table border=4 cellspacing=0 cellpadding=4>
<tr><td>
The bordered text
</tr></td>
</table>
<#nested>
<#nested>
<#nested>
</#macro>
<@do_thrice>
Anything.
</@do_thrice>
Anything.
Anything.
<@border>
<ul>
<@do_thrice>
<li><@greet person="Joe"/>
</@do_thrice>
</ul>
</@border>
输出l果Q?br /><table border=4 cellspacing=0 cellpadding=4><tr><td>
<ul>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
</ul>
</tr></td></table>
<#macro repeat count>
<#local y = "test">
<#list 1..count as x>
${y} ${count}/${x}: <#nested>
</#list>
</#macro>
test 3/2: ? ? ?
test 3/3: ? ? ?
在宏定义中用@环变?br />nestted指o(h)也可以有循环变量Q@环变量的含义见下节)Q调用宏的时候在宏指令的参数后面依次列出循环变量的名字,格式如下Q?/p>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
1. 0.5
2. 1
3. 1.5
4. 2 Last!
循环变量和宏标记指定的不同不?x)有问题Q如果调用时指定了循环变量Q那么多余的g可见。调用时多指定了循环变量Q多余的循环变量
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
${c}. ${halfc}
</@repeat>
Just repeat it...
</@repeat>
在模板中定义的变量有三种cdQ?br />plain变量Q可以在模板的Q何地方访问,包括使用include指o(h)插入的模板,使用assign指o(h)创徏和替换?br />局部变量:(x)在宏定义体中有效Q用local指o(h)创徏和替换?br />循环变量Q只能存在于指o(h)的嵌套内容,由指令(如listQ自动创建;宏的参数是局部变量,而不是@环变?br />局部变量隐藏(而不是覆盖)同名的plain变量Q@环变量隐藏同名的局部变量和plain变量Q下面是一个例子:(x)
${x} <#-- we see the plain var. here -->
6. ${x} <#-- the value of plain var. was not changed -->
<#list ["loop"] as x>
7. ${x} <#-- now the loop var. hides the plain var. -->
<#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
8. ${x} <#-- it still hides the plain var. -->
</#list>
9. ${x} <#-- the new value of plain var. -->
<#macro test>
2. ${x} <#-- we still see the plain var. here -->
<#local x = "local">
3. ${x} <#-- now the local var. hides it -->
<#list ["loop"] as x>
4. ${x} <#-- now the loop var. hides the local var. -->
</#list>
5. ${x} <#-- now we see the local var. again -->
</#macro>
输出l果Q?br /> 1. plain
2. plain
3. local
4. loop
5. local
6. plain
7. loop
8. loop
9. plain2
内部循环变量隐藏同名的外部@环变量,如:(x)
<#list ["loop 1"] as x>
${x}
<#list ["loop 2"] as x>
${x}
<#list ["loop 3"] as x>
${x}
</#list>
${x}
</#list>
${x}
</#list>
输出l果Q?br />loop 1
loop 2
loop 3
loop 2
loop 1
模板中的变量?x)隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用Ҏ(gu)变量globalQ下面的例子假设数据
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->
名字I间
通常情况Q只使用一个名字空_(d)UCؓ(f)d字空_(d)但ؓ(f)了创建可重用的宏、变换器或其它变量的集合Q通常U库Q,必须使用多名字空_(d)
创徏?br />下面是一个创建库的例子(假设保存在lib/my_test.ftl中)Q?br /><#macro copyright date>
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "jsmith@acme.com">
使用import指o(h)导入库到模板中,Freemarker?x)?f)导入的库创徏新的名字I间Qƈ可以通过import指o(h)中指定的散列变量讉K库中的变量:(x)
<#import "/lib/my_test.ftl" as my>
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
输出l果Q?br /><p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
<br>Email: mailto:jsmith@acme.com%3C/p>
jsmith@acme.com
fred@acme.com
可以看到例子中用的两个同名变量q没有冲H,因ؓ(f)它们位于不同的名字空间。还可以使用assign指o(h)在导入的名字I间中创建或替代变量
<#import "/lib/my_test.ftl" as my>
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}
输出l果Q?br />jsmith@acme.com
jsmith@other.com
数据模型中的变量M地方都可见,也包括不同的名字I间Q下面是修改的库Q?br /><#macro copyright date>
<p>Copyright (C) ${date} ${user}. All rights reserved.</p>
</#macro>
<#assign mail = "mailto:$%7Buser%7D@acme.com">
假设数据模型中的user变量的值是FredQ则下面的代码:(x)
<#import "/lib/my_test.ftl" as my>
<@my.copyright date="1999-2002"/>
${my.mail}
输出l果Q?br /><p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>Fred@acme.com
----------------------------------------------------------------------------
四.Freemarker与Strutsl合
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
<#assign logic=JspTaglibs["/WEB-INF/struts-logic.tld"]>
<@html.text property="vo.newsTitle" styleClass="input1"/>
五.用Freemarker生成Html面
import java.text.SimpleDateFormat;
import java.io.File;
import freemarker.template.DefaultObjectWrapper;
import java.util.Map;
import java.util.HashMap;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import freemarker.template.TemplateException;
import java.io.IOException;
import freemarker.template.Template;
public String make(Book book, BookFtl bookFtl) {
Configuration cfg = new Configuration();//配制
String templatePath = realPath + "/WEB-INF/templates/book";
String cDateStr = "book/" +
new SimpleDateFormat("yyyyMMdd").format(new java.util.
Date());
String filePostfix = ".html";
String path = realPath + "/" + cDateStr;
String fileTimeName = new SimpleDateFormat("yyyyMMddhhmmss").format(new
java.util.Date());
String returnFileName = cDateStr + "/" + fileTimeName + filePostfix;
String fileName = "";
File bookDir = new File(path);
if (bookDir.exists()) {
fileName = path + "/" + fileTimeName + filePostfix;
} else {
bookDir.mkdirs();
fileName = path + "/" + fileTimeName + filePostfix;
}
try {
//讄freemarker的参?br /> cfg.setNumberFormat("0.##########");//生成html文g时web.xml配制无效
//cfg.setEncoding();
cfg.setDirectoryForTemplateLoading(new File(templatePath));
cfg.setObjectWrapper(new DefaultObjectWrapper());
Template bookTemplate = cfg.getTemplate(bookFtl.getTemplateName());//模板对象
Map root = new HashMap();
root.put("book", book);
root.put("book2",book);
Writer out = new OutputStreamWriter(new FileOutputStream(fileName));
try {
bookTemplate.process(root, out);
} catch (TemplateException e) {
e.printStackTrace();
}
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
return returnFileName;
}
}
取Session中的?/strong>
${expression}
2.[]?q算W?br /> EL 提供.和[]两种q算W来存取数据?br /> 当要存取的属性名UC包含一些特D字W,??{ƈ非字母或数字的符P׃定要使用 []。例如:(x)
${user.My-Name}应当改ؓ(f)${user["My-Name"] }
如果要动态取值时Q就可以用[]来做Q?无法做到动态取倹{例如:(x)
${sessionScope.user[data]}中data 是一个变?br /> 3.变量
EL存取变量数据的方法很单,例如Q?{username}。它的意思是取出某一范围中名UCؓ(f)username的变量?br /> 因ؓ(f)我们q没有指定哪一个范围的usernameQ所以它?x)依序从Page、Request、Session、Application范围查找?br /> 假如途中扑ֈusernameQ就直接回传Q不再l找下去Q但是假如全部的范围都没有找到时Q就回传null?br /> 属性范围在EL中的名称
Page pageScope
Request requestScope
Session sessionScope
Application applicationScope
二、EL隐含对象
1.与范围有关的隐含对象
与范围有关的EL 隐含对象包含以下四个QpageScope、requestScope、sessionScope 和applicationScopeQ?br /> 它们基本上就和JSP的pageContext、request、session和application一P
在EL中,q四个隐含对象只能用来取得范围属性|即getAttribute(String name)Q却不能取得其他相关信息?br />
例如Q我们要取得session中储存一个属性username的|可以利用下列Ҏ(gu)Q?br /> session.getAttribute("username") 取得username的|
在EL中则使用下列Ҏ(gu)
${sessionScope.username}
与输入有关的隐含对象有两个:(x)param和paramValuesQ它们是EL中比较特别的隐含对象?br />
例如我们要取得用L(fng)h参数Ӟ可以利用下列Ҏ(gu)Q?br /> request.getParameter(String name)
request.getParameterValues(String name)
在EL中则可以使用param和paramValues两者来取得数据?br /> ${param.name}
${paramValues.name}
3.其他隐含对象
cookie
JSTLq没有提供设定cookie的动作,
例:(x)要取得cookie中有一个设定名UCؓ(f)userCountry的|可以使用${cookie.userCountry}来取得它?/div>
header 储存用户览器和服务端用来沟通的数据
例:(x)要取得用h览器的版本,可以使用${header["User-Agent"]}?br /> 另外在鲜机?x)下Q有可能同一标头名称拥有不同的|此时必须改ؓ(f)使用headerValues 来取得这些倹{?/div>
initParam取得讑֮web站点的环境参?Context)
例:(x)一般的Ҏ(gu)String userid = (String)application.getInitParameter("userid");
可以使用 ${initParam.userid}来取得名UCؓ(f)userid
pageContext取得其他有关用户要求或页面的详细信息?br /> ${pageContext.request.queryString} 取得h的参数字W串
${pageContext.request.requestURL} 取得h的URLQ但不包括请求之参数字符?br /> ${pageContext.request.contextPath} 服务的web application 的名U?br /> ${pageContext.request.method} 取得HTTP 的方?GET、POST)
${pageContext.request.protocol} 取得使用的协?HTTP/1.1、HTTP/1.0)
${pageContext.request.remoteUser} 取得用户名称
${pageContext.request.remoteAddr } 取得用户的IP 地址
${pageContext.session.new} 判断session 是否为新?br /> ${pageContext.session.id} 取得session 的ID
${pageContext.servletContext.serverInfo} 取得L端的服务信息
三、ELq算W?/strong>
1.术q算W有五个Q?????或div?或mod
2.关系q算W有六个Q?=或eq?=或ne?lt;或lt?gt;或gt?lt;=或le?gt;=或ge
3.逻辑q算W有三个Q?amp;&或and、||或or?或not
4.其它q算W有三个QEmptyq算W、条件运符?)q算W?br /> 例:(x)${empty param.name}?{A?B:C}?{A*(B+C)}
四、EL函数(functions)
语法Qns:function( arg1, arg2, arg3 ? argN)
其中ns为前|名U?prefix)Q它必须和taglib 指o(h)的前|名UC|?/div>
var="item"
begin="0"
end="9"
step="1"
varStatus="var">
…?br /></c:forEach>
OUT:
c:out>value 中的内容输出到当前位|,q里也就是把logininfo 对象?br />username属性D出到面当前位置?br />${……}是JSP2.0 中的Expression LanguageQELQ的语法。它定义了一个表辑ּQ?br />其中的表辑ּ可以是一个常量(如上Q,也可以是一个具体的表达语句Q如forEach循环体中
的情况)。典型案例如下:(x)
? ${logininfo.username}
q表明引用logininfo 对象的username 属性。我们可以通过?”操作符?br />用对象的属性,也可以用“[]”引用对象属性,?{logininfo[username]}
?{logininfo.username}辑ֈ了同L(fng)效果?br />“[]”引用方式的意义在于Q如果属性名中出CҎ(gu)字符Q如?”或者?”,
此时必M用“[]”获取属性g避免语法上的冲突Q系l开发时应尽量避?br />q一现象的出玎ͼ?br />与之{同的JSP Script大致如下Q?br />LoginInfo logininfo =
(LoginInfo)session.getAttribute(“logininfo?;
String username = logininfo.getUsername();
可以看到QEL大大节省了编码量?br />q里引出的另外一个问题就是,EL 从哪里扑ֈl(f)ogininfo 对象Q对?br />${logininfo.username}q样的表辑ּ而言Q首先会(x)从当前页面中L之前?br />否定义了变量logininfoQ如果没有找到则依次到Request、Session?br />Application 范围内寻找,直到扑ֈ为止。如果直到最后依然没有找到匹配的
变量Q则q回null.
如果我们需要指定变量的L范围Q可以在EL表达式中指定搜寻范围Q?br />${pageScope.logininfo.username}
${requestScope.logininfo.username}
${sessionScope.logininfo.username}
${applicationScope.logininfo.username}
在Spring 中,所有逻辑处理单元q回的结果数据,都将作ؓ(f)Attribute 被放
|到HttpServletRequest 对象中返回(具体实现可参见Spring 源码?br />org.springframework.web.servlet.view.InternalResourceView.
exposeModelAsRequestAttributesҎ(gu)的实C码)Q也是说Spring
MVC 中,l果数据对象默认都是requestScope。因此,在Spring MVC 中,
以下dҎ(gu)应慎用:(x)
${sessionScope.logininfo.username}
${applicationScope.logininfo.username}
? ${1Q?}
l果辑ּ计算l果Q即整数??br />? ${i>1}
如果变量值i>1的话Q将q回boolcdtrue。与上例比较Q可以发现EL?x)?br />动根据表辑ּ计算l果q回不同的数据类型?br />表达式的写法与java代码中的表达式编写方式大致相同?/div>
*
</c:if>
判定条g一般ؓ(f)一个EL表达式?br /><c:if>q没有提供else子句Q用的时候可能有些不便,此时我们可以通过<c:choose>
tag来达到类似的目的Q?br /><c:choose>
<c:when test="${var.index % 2 == 0}">
*
</c:when>
<c:otherwise>
!
</c:otherwise>
</c:choose>
cMJava 中的switch 语句Q?lt;c:choose>提供了复杂判定条件下的简化处理手法。其
?lt;c:when>子句cMcase子句Q可以出现多ơ。上面的代码Q在奇数行时输出?”号Q?br />而偶数行时输出?”?br />Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?/div>