该用户从未签到
|
一.Freemarker简介' ?+ a$ |3 u4 _, S5 X
二.环境搭建与配置$ f, H# B0 `- a! {
三.常用语法
& M9 P3 `7 b$ |9 q) H8 l2 m1 A四.与struts结合 O- f p! O3 |: V1 b$ X5 S
五.生成Html页面
c! ~+ b! X" v4 F! X/ i7 e- g3 l4 y3 t" X$ D2 r0 Q5 \
一.Freemarker简介) {4 g. i' l: @0 p
什么是Freemarker:.
' U0 ]5 c; F4 C& Z1 D3 z+ T* e bFreemaker是一个”模板引擎”,也可以说是一个基于模板技术的生成文本输出的一个通用工具.它是一个java的包,一个JAVA程序员可以使用的
5 E+ S7 ~: A2 @类库.本身并不是一个对最终用户的应用程序.但是,程序员可以把它应用到他们的产品中.
1 F% F7 Q- Z% x4 C X. nFreeMarker是设计为可以生成WEB PAGES.它是基于SERVLET遵循MVC模式的.这个思路是应用MVC模式要降低分离,网页设计人员和程序员的耦合.
% S' D/ b- r/ o8 F x0 G- q每个人都可以做他们擅长的工作.网页设计人员可以改变网页的面貌,而并不需要程序员的重新编译.因为业务逻辑和页面的设计已经被分离开了! ]: }' C9 S. ]( k
.模板是不能由复杂的程序片断组成的.即便网页设计人员和程序员是一个人. 分离是有必要的.它能使程序更加的灵活和清晰.
5 G& R; I: t$ x3 D ]& w# H虽然Freemarker能编程,但是它并不是一个编程语言.它是为程序显示数据而准备的.(像数据库SQL语句的查询.)以及.Freemarker仅仅是利用模
" v$ F+ A1 c; W& N0 U. u板加上数据生成文本页面.8 p' ^4 t6 o M5 c$ a4 `
Freemarker并不是一个WEB应用程序框架.可以说是一个WEB应用框架的一个组件.但是FREEMARKER引擎本身并不了解HTTP或者SERVLETS.它只不过; @9 a J. w9 P& i$ V) [0 s
生成文本而已.注意,它是MVC框架的一个组件(如STRUTS),也可以在模板中使用JSP标签.
* ?5 z6 W3 @" q" I% O& ZFreemarker下载地址为:http://www.freemarker.org/index.html
7 b$ w/ e* {9 ~4 N& b. i1 l一般的用途:- T( y6 L4 H; ~; ]
l 能用来生成任意格式的文本:HTML,XML,RTF,JAVA源码,等等.! C% ^+ t% T: e; Y3 a$ g# h
l可以更好的嵌入到你的产品中,轻量级的.并不需要servlet环境.不依赖javax.servlet.classes.
8 |& y7 U+ G: G5 Kl可插入的模板读取器:你可以从任意的源码读取任意的模板.本地的文件,数据库等等.
# r7 m( y6 u% i5 B# nl你可以做任意你想生成的文本.存储为本地文件.可以用来发送EMAIL或返回到WEB浏览器中.+ j( V' p& R7 X2 z2 h5 c' Z9 j
+ u0 I6 K% K) s
强大的模板语言# s& R% @# G- c8 z
l完整的指令:include,if/elseif/else,loop.2 w- r( I* V. X2 V
l 建立和修改模板中的变量.
* ^# L; V& S9 E4 |l 能用复杂的表达式在任意地方指定变量.
$ n8 o7 s5 R8 e/ Q9 o T2 F( gn字符串操作:concateration,sub-string,uppercase,capitalize,escaping.等等
4 Y* ^( C& Z( q' a' A* h' {& fn十进制数学计算.) b2 l4 J8 h" O) Y; s ^ u
n BOOL4 _* I% J$ J$ x" c* C" D1 X2 r
n读取数组和相关的数组元素./ v: E# Z% C) `8 c
n可以自己添加特殊的计算方法.0 j- z+ C/ e" T
l宏指令$ k3 L3 c4 A. j8 M4 }
l 命名空间用来创建和维护宏指令库或者把大的项目分成许多模块.并不用担心命名冲突
0 \6 S5 s3 X. K% M1 z6 V二.环境搭建与配置
# K9 i0 f5 T. S3 c! Z<!—freemarker初始配置-->: H" x8 [( A" x- j f0 O1 H
" c) h3 g' J. f/ b) ]
<servlet>2 X2 |2 u8 F3 }2 N9 u
<servlet-name>freemarker</servlet-name>
; o" s& i0 v5 v5 r<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
2 S9 j% M; a& N4 U; Z, u @2 N: V5 t<init-param>
- K4 m, W. t4 @2 V! }0 T( U/ |<param-name>TemplatePath</param-name>1 P# U( z8 r' X; n8 y% p/ q8 k( D
<param-value>/</param-value>
9 S9 ~1 T- C) t& d3 y$ l</init-param>
) Z. A0 J. U) m: J( v: x<init-param>/ L7 z3 ?8 w7 m% A! m
<param-name>NoCache</param-name>+ g: Z0 u! x G* t( D
<param-value>true</param-value>
; M* X6 `: _5 n</init-param>
- i. I$ }; w0 z$ P<init-param>+ z6 I8 _+ V' ~
<param-name>ContentType</param-name>( q: w) G$ Y1 L- c. E6 N4 D
<param-value>text/html</param-value>
" @1 ^' d0 ^! S8 n, g3 b4 l& z</init-param>% |" p G) O$ F! S* u* C& o
<init-param>
, f: W* G7 e V# w<param-name>template_update_delay</param-name>
, ^6 [; l, ]; z0 x<param-value>0</param-value>
/ _$ A7 s( w" i* a% z</init-param>0 ]3 L$ s9 V H+ J3 ?
<init-param>
4 z5 V; I1 p' v6 F<param-name>default_encoding</param-name> t& H" R( o2 z- q# P
<param-value>GBK</param-value>* Q" j5 Y8 @4 g; R4 f
</init-param>
$ d2 S$ }* a+ \0 O: ^" }<init-param>5 |0 H4 Z8 o- ]# _
<param-name>locale</param-name>
9 a* v* q1 }- X& l: x<param-value>zh_CN </param-value>
b% J5 `* h7 i. `/ e8 h9 p" ]+ a5 a</init-param>
+ J% `+ k; d) j" t% R<init-param>
9 G# u# P8 J4 [<param-name>number_format</param-name>
$ C% w+ C0 _ `3 K8 Y9 S/ u<param-value>0.##########</param-value>
' n* H" ?+ S5 g</init-param>
v" q. k# E5 Q0 A' m; |5 I<load-on-startup>2</load-on-startup>
/ n0 Z8 y" e4 Z</servlet>
* M4 q5 {8 E8 A9 S3 n1 }) r- \+ h1 \<servlet-mapping>& g& C8 Z! X: n6 } N5 x- m
<servlet-name>action</servlet-name>
. _/ N; Q* s3 k; z& W+ I<url-pattern>*.do</url-pattern>
{; |1 I0 M$ T" q* n& u</servlet-mapping>8 v$ r0 F+ ]! o$ e/ M; J1 h
<servlet-mapping>
2 B, g4 ^0 n: `* q- z7 c' @3 I<servlet-name>freemarker</servlet-name>
& E& u9 |2 h. j! k4 m* t<url-pattern>*.ftl</url-pattern>
6 A1 O4 M( e5 ]4 c$ |" q</servlet-mapping>/ I- E0 `5 q0 J5 g7 G9 Y
) G7 y8 L& X1 n6 w& O l% |, a----------------------------------------------------------------------------8 Q1 ?3 V5 I+ R0 T/ X4 i7 s
三.常用语法
0 M3 n) s6 E) p1 OEG.一个对象BOOK9 V s, C* f# s( N1 G+ ~7 ~% V
# p5 o- e% e4 ]8 ~4 P
1.输出 ${book.name}
. F$ h$ m8 X6 [1 p! m' S- ]5 K空值判断:${book.name?if_exists },
1 ]# F8 W) I7 d2 L; R% b7 B" R${book.name?default(‘xxx’)}//默认值xxx
) p) S: M" ]; f' y$ e0 f${ book.name!"xxx"}//默认值xxx3 `: L2 d8 X! B
日期格式:${book.date?string('yyyy-MM-dd')}9 X3 e# `' L1 U' ]
数字格式:${book?string.number}--20/ y- J! e5 ?- w) J
${book?string.currency}--<#-- $20.00 --> X' d* F4 @. G4 a$ y
${book?string.percent}—<#-- 20% -->' W% U6 {% L& G8 Q& z9 Z
插入布尔值:
& r( F+ C& s/ c3 R<#assign foo=ture />4 n/ f. C) ]% X" C3 h% D
${foo?string("yes","no")} <#-- yes -->
% _$ x9 b, {" q3 w2 p" s2 }2 g
5 w; q9 J3 C% z7 c4 O# `- L1 b& ?
/ |; [2 @. M( ?" z( w5 D0 R& |) S: J8 s2 B: z- v2 ] c
% m! l! Z/ h; y: Z( c; Q+ ~! B6 |
2.逻辑判断6 @3 V. l5 e( h( k- p
a:
. s/ I% l+ ]- f7 ^<#if condition>...
! w5 \. T* @4 ~. \ l8 ~' L<#elseif condition2>...
3 g0 d& R6 U' R2 r' P2 L- o<#elseif condition3>......
- j/ ^- D& S+ y<#else>..., x: \* w8 t1 D3 M$ @
其中空值判断可以写成<#if book.name?? >
+ U: a$ k9 A1 L! C
4 j0 F/ ` S, ?8 f {& m) o</#if>
" G7 `$ V# f: A3 |* A8 q6 d+ M0 V9 b6 t# b {# l- Q
b:" G6 w1 w3 c* { K z- ]7 E
<#switch value>
" ^ O. H- r, ?4 z' o+ a<#case refValue1>
' K n: X. y4 x C...6 h, e* ?( F8 i2 U
<#break>6 A4 ]/ b& m' b; p- q
<#case refValue2>9 Q# k! j: m ^, A& `( x
...
! z# _& l/ }3 W4 f. V<#break>* @- J3 A$ @" h& G" u3 S& s" r
...
) Y4 x% V, v" b: n. ]: P: ?4 @3 H. Y4 E<#case refValueN>
' w$ r9 E4 a. H8 P) e6 o% M...
& m$ v( ?0 R a: q8 t! m% ~<#break>3 }2 {$ L# @! H1 ]7 X& B
<#default>! X6 t P. t+ p& d; E7 V2 m
...
5 {* N( [/ Z' E! w* E% B( s</#switch>
( M) j1 r. s' J" ^4 e; q f3 U$ Y( F5 e, S4 u. k% J+ X5 d4 `2 Y9 i' |* Y
3.循环读取6 ^6 z1 E; p; u/ S1 p
<#list sequence as item>" v4 _# q' k- g/ V4 `
...% I9 N1 ?/ O8 Y# ]
</#list>" g+ N* W q y, k
空值判断<#if bookList?size = 0></#list>
% P# w8 S% b2 v8 D2 b5 O; M8 Y5 @8 H/ D6 d, c. J) J
e.g.# c4 G& P7 L) p
<#list employees as e>: w! ]! Z( E, n V" v) n- S6 n
${e_index}. ${e.name}
4 u* m9 V5 z% Y" Q* ]7 I8 h9 V4 q</#list>( H7 V" b( I; X6 f% g8 i# d
输出:
4 M( s! N( ^% M( A' A1. Readonly% p# v3 T2 ?5 @# A6 N, T/ Y
2. Robbin
0 c* [# E+ i# N+ d9 A3 B1 W
' x2 o% ?2 O; n4.FreeMarker
$ [ K( `8 V' Q8 V% \5 a. y' _; i3 S1 \; g8 R% }' x
3 宏/模板' G! z& f" D q; O
宏Macro' r/ o6 X% y& [5 k) i. q% @8 O! S! ]
宏是在模板中使用macro指令定义! Z8 e& |: j {
l.1 基本用法
; L' \7 I* B$ k; k; h7 p' [宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是一个例子:3 u! _; p0 {6 Q& R3 H8 F
<#macro greet>
1 Y8 c& V$ f+ k5 }7 o( [# [( r<font size="+2">Hello Joe!</font>
1 |. T: ]" X0 y! \+ X9 v</#macro>7 G0 w7 ]* W! [
调用宏时,与使用FreeMarker的其他指令类似,* i i4 V7 L. m3 \, j% J9 j2 n: ^4 ?
只是使用@替代FTL标记中的#。* _- v+ |& X( s. @0 \' c
<@greet><[url=]/@greet[/url]>
( b3 X" J; L* i2 M g; S<#--<@greet/>-->
, y; x% j; E0 C" R, D! {: m7 } M, j4 ~$ K }1 @/ @2 K W
在macro指令中可以在宏变量之后定义参数,如:$ ? [$ R( d- {5 p6 ?
<#macro greet person>
; h' C# C. o5 O3 B+ o# h<font size="+2">Hello ${person}!</font>6 X9 L1 @6 |9 ~" W! t4 D4 m$ U
</#macro>9 F* I' {: R. Z& n- C& z: \
可以这样使用这个宏变量:& ?7 M- q# t8 R2 b7 t
<@greet person="Fred"/>
( k( Z( k: H% e; _* n8 T但是下面的代码具有不同的意思:2 C- w/ l1 V; I' m n. g
<@greet person=Fred/>
, K5 w; p: O& Z q/ x这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式。1 \/ Z) L: y. |
; \- D' V! q; v( L6 l4 D- C宏可以有多参数,下面是一个例子:
9 _' z# v2 _# d& I' h+ H% A<#macro greet person color>5 ]8 o4 T" q, z
<font size="+2" color="${color}">Hello ${person}!</font>0 R! S3 R: X; t% y' J! i
</#macro>
* s. H, o/ w2 | r: p& p可以这样使用该宏变量,其中参数的次序是无关的:, b, e3 O; l2 I. I' I
<@greet person="Fred" color="black"/>
2 ~2 w9 Z/ z! @- e( A! T7 P& y可以在定义参数时指定缺省值,否则,在调用宏的时候,必须对所有参数赋值:
6 N& o/ x" `1 I$ v+ i9 ~<#macro greet person color="black">. _# y- P- y+ j8 J6 f
<font size="+2" color="${color}">Hello ${person}!</font>
O" h: f6 d: c3 w* i) l3 I% v2 z( j</#macro>
8 `2 K9 N& T( Z3 h注意:宏的参数是局部变量,只能在宏定义中有效。: K, J# S& b8 X5 Y
% A$ [( x( t6 ]( }& B4 a$ @
在宏里嵌套内容- j8 r. m# `7 x6 Z
FreeMarker的宏可以有嵌套内容,
/ z9 ?9 j: r% z6 [$ u<#nested>指令会执行宏调用指令开始和结束标记之间的模板片断,举一个简单的例子:9 b o4 N- b7 p' O% T+ @- H9 L
<#macro border>
' }" N6 `1 c j! E; c) B4 P<table border=4 cellspacing=0 cellpadding=4><tr><td>0 M8 U; d+ I2 \- L, ]
<#nested>
3 C' A2 f7 H, x8 H* Y& i</tr></td></table>
, K5 D, g: i1 ?6 c" k" C; D7 b6 p</#macro>/ g* J+ I3 u+ h2 c g
执行宏调用:2 O0 |; B2 P9 p8 R N
<@border>The bordered text<[url=]/@border[/url]>, n, u r$ a8 A5 ?/ u% T5 ^
输出结果:6 H; V. }1 R; E) ?- b( \
<table border=4 cellspacing=0 cellpadding=4>& K/ ]! Q! v* e, ^' ^
<tr><td>' y6 Y/ T, f0 T3 _! F& j9 y- y& v
The bordered text
' h( N/ ]; M4 }2 ^, m- z! z</tr></td>( e9 |. B: {( D" u7 ~ Q W$ c* d
</table>
% o( x" G, q3 D! b ]/ ?% ^. o ] a<#nested>指令可以被多次调用,每次都会执行相同的内容。
( E# ^/ S" {2 z' E9 @6 J- D* F8 @<#macro do_thrice>
+ a) u5 V9 ^ e' V<#nested>! d y, ~" M7 B& f5 C) p2 u& E
<#nested>! o2 q; L7 l! R6 \' z' B% H
<#nested>
" ^+ w( [- T' C</#macro>
; h4 [* o( _7 W% G2 x+ Q/ e- `
<@do_thrice>- X. [& F+ A4 m( \- D* J0 f6 K& F
Anything.
4 h5 ~1 B; O6 l8 B7 A6 d<[url=]/@do_thrice[/url]>
: U& `# M5 w9 K% w( nFMPP 输出结果:$ O3 L0 ^: C; G- k; P
Anything.: S1 ?, @- d/ z
Anything.
9 ^; T; {$ `4 ?7 O" U8 v8 [4 t2 YAnything.' \! n/ h) C% [, u" ]
嵌套内容可以是有效的FTL,下面是一个有些复杂的例子,我们将上面三个宏组合起来:
1 k. p7 B. A1 f<@border>
( i: } g& l' a8 q<ul>3 a, O3 V( w* U% J P* D- ]! N
<@do_thrice>
& V9 e! I# {+ E- G<li><@greet person="Joe"/>( R# E5 B; s+ l3 b
<[url=]/@do_thrice[/url]>/ L. Z6 @, O I2 g
</ul>
5 q8 c3 P/ [$ T% n0 Q( v<[url=]/@border[/url]>
/ \1 v/ y- _; f输出结果:
/ o6 a; a, d$ ~* |! M, d, `<table border=4 cellspacing=0 cellpadding=4><tr><td>
* Q& H6 j2 I6 b; q; x- [' O" p<ul>- r. Y3 m) B" Q& c/ G# E% n
<li><font size="+2">Hello Joe!</font>: l0 t, m& @: X0 r8 J p' u" \0 P
<li><font size="+2">Hello Joe!</font>
8 W& f4 ?1 Q9 u7 a5 p- h K+ y8 Q<li><font size="+2">Hello Joe!</font>
5 t" g' _( Y8 }</ul>
+ H7 W! |9 ^8 O- x- E- N$ P& D</tr></td></table># P: E& o9 p( \, K8 ~
宏定义中的局部变量对嵌套内容是不可见的,例如:
- S [% Y$ m" ]! G( g- R8 a; p<#macro repeat count>
) @7 [* t( v' P* J9 u( K% M, ~ d5 q<#local y = "test">0 d& w2 t. n: K
<#list 1..count as x>6 f* n5 h" v: @
${y} ${count}/${x}: <#nested>
0 [8 N# @( ^9 q; \7 d6 P* x2 `</#list>
! ]; \$ I7 D" _</#macro>
. n$ i3 K4 Y }. ~3 ^) t<@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}<[url=]/@repeat[/url]>8 h5 g- ]+ v+ S; k" d( G
输出结果:7 n' |+ l$ P6 n# G3 \
test 3/1: ? ? ?% c' M# A2 D4 w
test 3/2: ? ? ?+ t" o+ A' |7 |, o( ]: G- s
test 3/3: ? ? ?
! x/ w9 t( V8 R* ~, r
' F2 P% n! S9 [* \- ~7 h在宏定义中使用循环变量
4 B) A& ]! Y/ F9 @2 R& qnestted指令也可以有循环变量(循环变量的含义见下节),调用宏的时候在宏指令的参数后面依次列出循环变量的名字,格式如下:2 \" L+ M: z+ Q0 r' Y0 v4 S
<@ macro_name paramter list; loop variable list[,]>& U# b2 y! \0 Y+ d4 {
例如:9 ]) C! q" Z* K3 [5 x- Q- P
<#macro repeat count># P* S7 B2 @& v% o! n& k
<#list 1..count as x>
- I3 t% o/ G( p4 Z' A<#nested x, x/2, x==count>
! P# P7 U- r" a3 b9 G: @</#list>6 e' s$ p S& S
</#macro>+ P7 F9 i; m6 i$ `/ X1 Q7 @
<@repeat count=4 ; c, halfc, last>/ |- x8 ?( P% W0 r- s! Z1 C* U
${c}. ${halfc}<#if last> Last!</#if>
9 o1 [& V( N* _. f* ?- [3 Z<[url=]/@repeat[/url]>
! ~4 B9 I; n) i T1 i0 t. b这里count是宏的参数,c, halfc,last则为循环变量,输出结果:
; B6 z7 F2 H/ r) P/ F/ ~1. 0.5
% w9 t0 j, j& }) t$ o0 D2. 1
# V* a4 g( J( S6 o8 t2 \3. 1.57 z/ X H$ g4 Y& L% f0 G7 m
4. 2 Last!
5 ]8 s( t' y0 F# o/ P循环变量和宏标记指定的不同不会有问题,如果调用时少指定了循环变量,那么多余的值不可见。调用时多指定了循环变量,多余的循环变量
. x6 [$ ^8 y4 e- Q% O& ]* O6 ~' y. G不会被创建:
8 L- _) V* I! k' G2 q+ A<@repeat count=4 ; c, halfc, last>
* J. e2 c3 B* b5 |& }( d${c}. ${halfc}<#if last> Last!</#if>- M5 e2 e9 u6 j# ]
<[url=]/@repeat[/url]>
* N/ O$ }0 a2 R5 ]6 Z5 @<@repeat count=4 ; c, halfc> H1 ?, U0 Y9 d$ ?* p" K
${c}. ${halfc}
- w, F3 c% G! H<[url=]/@repeat[/url]>
0 |$ `& s' C+ z4 {& b* Z* D- k<@repeat count=4>
8 u4 z* n" f% ^$ `8 g. qJust repeat it...
5 u, i1 a% _- ~; s- T/ {1 K<[url=]/@repeat[/url]>
% R! W, N/ I1 \在模板中定义变量
3 p& F* e* T4 T8 i在模板中定义的变量有三种类型:. l S6 ?2 K3 n) K0 y
plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换。4 ]6 x1 Y, ?) s
局部变量:在宏定义体中有效,使用local指令创建和替换。
8 O, Y- M; m6 m2 K4 U循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量
/ K& x$ Y. Q- c1 [" u9 V局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:
5 v" L* n! C! H, k; l7 x<#assign x = "plain">8 n# r4 h4 i3 E/ \3 D
( v; g4 X" f( c/ x) w${x} <#-- we see the plain var. here -->/ C7 Y" K, N7 ]" C! K3 E x' R
<@test/>
. i$ D, \5 Z9 X( g" T: t+ J9 g6. ${x} <#-- the value of plain var. was not changed -->' U3 T V2 {. d3 ]' L& z! l* o! Q! N
<#list ["loop"] as x>, q- E, J# E2 e0 T
7. ${x} <#-- now the loop var. hides the plain var. -->
/ l/ x8 I; W& o<#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
4 P7 K$ y4 m. ?7 H1 q: e' B8. ${x} <#-- it still hides the plain var. -->4 v6 ?: A9 y# e! X5 \7 W' k. q! t
</#list>
3 |) `8 z4 |% K# B9. ${x} <#-- the new value of plain var. -->9 \3 M1 v$ \* o& O
<#macro test>
( C T4 P+ g7 T. E& q1 V1 G2. ${x} <#-- we still see the plain var. here -->
Z! y" S4 @) b- `* _* {! g0 \- f<#local x = "local">" W8 N6 M5 M% Q; E- W. P+ Q
3. ${x} <#-- now the local var. hides it -->
7 E9 A2 U* g3 y& a# G<#list ["loop"] as x>
- n5 l2 _0 @' U3 d4. ${x} <#-- now the loop var. hides the local var. -->" ` X/ S p% Y9 Z7 ~1 O2 e
</#list>
2 i y- e" G3 O1 O2 Q' N" ~2 O5. ${x} <#-- now we see the local var. again -->: K e" @! ]- H3 J
</#macro> r+ m% j2 D% K0 A) D! D
输出结果:
5 e2 ^( v& F; R8 w# v+ v" ]. g1. plain8 i# o+ `* x' i6 w- D( Q
2. plain
# k4 F$ V1 d% K5 \7 `+ a% n5 f& b3. local
6 l4 S4 t$ m2 P/ h* }" W4. loop3 b( n5 ^" C; Z& F `& r
5. local" S- }' J: O( V! B/ v8 M
6. plain
: P* ?( [. e" [3 _, N# c' ^7. loop
; p8 l7 y, g4 y- w8 f8 u$ y; ^) L: ^8. loop" r, B' R: D+ B( x& V3 _ B% S
9. plain28 q- u1 n7 w9 D6 W- s; S x
内部循环变量隐藏同名的外部循环变量,如:9 S" W, Q& b% P. K% \$ R" |
<#list ["loop 1"] as x>
! W7 |0 _+ F8 _( {0 v' {${x}# O9 X' M3 L/ W# k$ U" B ~/ N
<#list ["loop 2"] as x>+ R6 Q4 _4 {* y- a- F' c# ]2 \8 H
${x}" J& A7 F" \+ ?4 \3 p+ s. w
<#list ["loop 3"] as x>
( ?+ ]# s/ S; l* I4 a${x}
- \+ D) V: f3 X% @</#list>
" ~1 E0 ]$ o4 T+ a. ^7 _9 {${x}4 s. l5 l5 u0 U! q9 C0 C5 u
</#list>$ Z( ] e0 E# `7 e* L
${x}
# B" a1 S5 J$ [7 F6 K: T</#list>5 f+ J; a" x( I7 J( x& M0 i; M* w
输出结果:
) U& q3 ~6 F$ K# j/ oloop 1
! G: Z2 @: c3 ~# j( q @9 w9 oloop 2* t5 l& A$ Q' O/ u: Z+ e' Y3 Q3 Z- I
loop 3
! V' r7 ^% ^+ X5 T) Rloop 2: m4 A; ~8 W% S( L; O7 U; E
loop 1( B! l" n9 U' R) z# o
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据
5 e" W2 X. h# w5 _模型中的user的值是Big Joe:" _6 l/ }. g; G& R: l: _
<#assign user = "Joe Hider">
/ V _) c- U" N, m1 G. N, A& ^- `${user} <#-- prints: Joe Hider -->
, c2 C, f+ p9 v( O/ R${.globals.user} <#-- prints: Big Joe -->9 W4 z1 X0 i3 T0 I
名字空间 V9 }! [. [, G* Z4 j r2 a L6 l
通常情况,只使用一个名字空间,称为主名字空间,但为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字空间,# s1 R% w# a6 p4 u
其目的是防止同名冲突( m: K2 c0 P: z6 Z6 W% ?
创建库
3 R! E9 x, Z4 B下面是一个创建库的例子(假设保存在lib/my_test.ftl中):) W' H! N3 T+ m
<#macro copyright date>
/ M! w. {3 m5 B' p& K0 J( [- K<p>Copyright (C) ${date} Julia Smith. All rights reserved.
. f- c8 r' U0 N! `- {9 A2 N<br>Email: ${mail}</p>
, Z/ I! v6 `! z' M</#macro>6 O& A0 B) I0 x3 w
<#assign mail = "jsmith@acme.com">4 l2 M8 k3 v. d- d1 U
使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量:
|& _, e! j! G2 w' m<#import "/lib/my_test.ftl" as my>
. @8 O3 F* R( A<#assign mail="fred@acme.com">
( x9 k& D0 y, ^$ {( E<@my.copyright date="1999-2002"/>' S2 X! }% k& x- r3 C% l- f
${my.mail}' @2 T( z( \# U" o: ]" N
${mail}
$ d: F$ ^' |3 X) d& J3 P输出结果:' x+ K( v% ^$ n/ G, I
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
8 D+ U6 @3 D( O, x G- S& ~<br>Email: jsmith@acme.com</p>
8 X1 V% f# ^4 o: W' x1 ~9 Ajsmith@acme.com
$ u8 F- x r1 f1 v5 Zfred@acme.com
. n" q) g: W# ]( w, y6 \" u" B可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间。还可以使用assign指令在导入的名字空间中创建或替代变量9 z, X/ t! r4 J# j( V
,下面是一个例子:: i M6 h2 e) n' u$ f5 R
<#import "/lib/my_test.ftl" as my>
' f+ S4 K# [; y: B1 r${my.mail} m G& \: \0 ? j/ I0 _7 |
<#assign mail="jsmith@other.com" in my>; l4 V8 V q; s# k
${my.mail}
7 J. [: _+ G0 Q6 x" w输出结果:1 p4 @* v6 |' I' J" b) s P
jsmith@acme.com
" S. F Y5 p+ \jsmith@other.com2 z3 M# ?, \; t" \$ W. V
数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库:
: }% w7 h, s R6 p: Y<#macro copyright date>2 u) M- b0 r1 R# D6 u. T7 B
<p>Copyright (C) ${date} ${user}. All rights reserved.</p>" d/ v. X: _* _, T! N; h
</#macro>* K+ I' E+ {3 E) G
<#assign mail = "[url=mailto:%24%7Buser%7D@acme.com]${user}@acme.com[/url]">
7 y, B8 a+ b w+ z% u6 r! m$ Z假设数据模型中的user变量的值是Fred,则下面的代码:
, |4 v6 ^# ?2 `) v<#import "/lib/my_test.ftl" as my>5 ^/ N( v4 B1 o
<@my.copyright date="1999-2002"/>6 G' F: {6 H7 h/ Y3 w/ r
${my.mail}; d$ e8 Y+ \8 `% L. _+ O$ W$ E2 c
输出结果:
' O$ j# `2 a. o3 l<p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>Fred@acme.com
( Y6 a* ^$ O, `: J, C* s- P/ J+ ]8 g. ^: Y% D
四.Freemarker与Struts结合
9 I: @3 Q9 H7 N8 Q) y+ ^# _9 @1.输出文件换成以ftl格式的文件/ T m/ K, F! L' L) F, ?
E.G. v& X: W' d: ?
<action name="bookActionForm" parameter="method" path="/bookAction" scope="request" type="example.BookAction"
- [4 J, l4 f& [8 Zvalidate="true">7 a% \; V) o8 a5 ^6 J0 R( |
<forward name="list" path="/index.ftl"/>
. b! Y7 o8 k5 {! x* M, c, U</action>* n, N2 b. N& ?% i" |/ ?
2.使用struts,jstl等标签7 P, z. }! O; w( |2 ^
a.导入à<#global html=JspTaglibs["/WEB-INF/tags/struts-html.tld"]>+ v( t7 i2 @% t F
或<#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]>" Q/ w7 T* T- X9 r
<#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]>
0 n* m8 Q/ j2 `/ i8 W<#assign logic=JspTaglibs["/WEB-INF/struts-logic.tld"]>9 \) w% I4 i7 K4 I1 n5 M; V
b.使用à<@bean.page id="request" property="request"/>, d. {' I& n% W# s% c# g }
<@html.text property="vo.newsTitle" styleClass="input1"/>3 @2 D0 L0 T3 i' p; U- x$ x
五.用Freemarker生成Html页面
4 ]$ v( v1 ^* i3 V5 V! Y例子:MakeFileManager.java$ f: X$ z+ T$ ^1 l
1 f5 p' f( R, [& ?package example;, w/ M5 j: N6 p' @7 h1 |% S5 q
import freemarker.template.Configuration;* x7 L- Y& y. _# j2 m
import java.text.SimpleDateFormat;
# Q% [+ r3 q, b' ^. p' d Z0 y: dimport java.io.File; E8 }% b L0 Y" ]1 n2 l) F# Q
import freemarker.template.DefaultObjectWrapper;
: C+ f; N- a# v0 b2 timport java.util.Map;
4 Q, ?4 r2 k- Mimport java.util.HashMap;
3 D0 b; p- [% ]' Simport java.io.Writer;7 C' C2 R* u4 ?2 g2 Y4 ?' m: a
import java.io.OutputStreamWriter;
% I& q/ V0 I- k" Himport java.io.FileOutputStream;; g. ^9 d$ _% a$ a4 A
import freemarker.template.TemplateException;
* {+ e8 Q# i' ~: q' O8 w, d6 k Cimport java.io.IOException;
- w4 k* }) w0 T9 z* s- aimport freemarker.template.Template;9 t0 c, I5 A' J6 y- u
public class MakeFileManager {
" Y" c. B" p1 M; A2 [ Tpublic String make(Book book, BookFtl bookFtl) {
- \- H+ E; {, g) \' JConfiguration cfg = new Configuration();//配制
w, H0 Q: ^; [' R2 S) Z3 g$ CString realPath = bookFtl.getRealPath();3 e0 ?; t3 A- Y8 C; Y+ J \
String templatePath = realPath + "/WEB-INF/templates/book";/ X) U4 E. \8 X, r6 ?* U' Z1 l
String cDateStr = "book/" +
( y. c: X) E2 a2 T0 L7 ]new SimpleDateFormat("yyyyMMdd").format(new java.util.( R" P* s0 w" X
Date());
0 M0 o) n8 j6 h: H# QString filePostfix = ".html";
$ N1 \: }2 K6 PString path = realPath + "/" + cDateStr;* b4 s# @' d( E
String fileTimeName = new SimpleDateFormat("yyyyMMddhhmmss").format(new8 l& J( u U+ O* O; l' V3 B
java.util.Date());
4 o* d! u9 b+ w/ |" D2 k i3 ZString returnFileName = cDateStr + "/" + fileTimeName + filePostfix;
8 I; d H0 y7 P; e% ZString fileName = "";
# s% a! f2 }# MFile bookDir = new File(path);1 @1 d8 u1 g. p* d( a: e6 Z
if (bookDir.exists()) {3 n% ^7 O3 @/ b' {
fileName = path + "/" + fileTimeName + filePostfix;
& B2 z$ S1 O4 ]; o9 W} else {
8 s+ ^# _) E0 j/ @bookDir.mkdirs();
- @8 o' x) E8 U9 [" y5 f ufileName = path + "/" + fileTimeName + filePostfix;5 n: i3 n1 p& r0 f2 Y
}( M+ Q) ^7 Q9 ?( n$ H8 h: e
try {
' B& X) }, {% ?% t! J- r6 M//设置freemarker的参数
4 a# V# R% T$ S: C* xcfg.setNumberFormat("0.##########");//生成html文件时web.xml配制无效7 c" i/ c5 e) Q5 k+ {. ?
//cfg.setEncoding();
! {7 p e$ Y) ~. dcfg.setDirectoryForTemplateLoading(new File(templatePath));
1 a* e: F) t c6 L; Q3 jcfg.setObjectWrapper(new DefaultObjectWrapper());
- [2 w6 k* p, _2 b- q z7 UTemplate bookTemplate = cfg.getTemplate(bookFtl.getTemplateName());//模板对象
% T0 P1 ]+ s* K/ xMap root = new HashMap();* t$ }3 A& h3 f" [& l
root.put("book", book);4 w# X S/ S$ `2 N' x
root.put("book2",book);
! y7 Z: V' P) xWriter out = new OutputStreamWriter(new FileOutputStream(fileName));
8 k% c% S& V6 r( m6 h. e4 C' stry {3 ~9 q# N8 }: S- R) ]
bookTemplate.process(root, out);
. d& e6 P: Q* E1 R! u( Y# p. G/ w3 z} catch (TemplateException e) {2 L+ ~$ B2 M0 j
e.printStackTrace();! j# c; U0 Q+ I+ F7 P1 @) h
}4 \* w7 ?2 m0 L! @$ m9 Z/ N! i
out.flush();" ~( e8 v" v$ Z) t! u
} catch (IOException e) {+ O4 `' d7 |( Z
e.printStackTrace();4 C a a0 e; l& c- _( Z& y& p$ |
}
' T: {8 @5 [& |" {/ Greturn returnFileName;* o5 w& E0 G5 ~" v
}: i k! G0 H$ u( w
}4 V% Z7 ?7 v4 K
6 n. H* c4 W9 ] |
|