在B/S程式設(shè)計中,常常有美工和程序員二個角色,他們具有不同專業(yè)技能:美工專注于表現(xiàn)——創(chuàng)建頁面、風格、布局、效果等等可視元素;而程序員則忙于創(chuàng)建程式的商業(yè)流程,生成設(shè)計頁面要顯示的數(shù)據(jù)等等。
很多時候,要顯示的資料在設(shè)計的時候并不存在,它們一般是在運行時由程式產(chǎn)生的,比如執(zhí)行“價格不高于800NT的USB Disk”查詢的返回結(jié)果。這種技術(shù)需求產(chǎn)生了JSP等Scriptlet,JSP十分強大,但是也常常被濫用,并導致一些不良的后果
- 將邏輯和表現(xiàn)混合在一起。
- 破壞了美工和程序員職責的正常分解。
- 使JSP頁面難以閱讀和維護。
模板引擎就是為了解決上面的問題而產(chǎn)生的。在設(shè)計HTML的時候,我們加入一些特定指令來指定要插入哪些數(shù)據(jù),這些加了特殊指令的HTML或者其他文本,我們稱為模板(Template)。而模板引擎會在輸出頁面時,用適當?shù)臄?shù)據(jù)替代這些代碼。
模板和嵌入JSP的HTML是不同的,模板指令只有很有限的編程能力,可以避免混入商業(yè)邏輯。
三萬英尺俯瞰FreeMarker
簡單的說,F(xiàn)reeMarker就是一種用Java編寫的模板引擎,它根據(jù)模板輸出多種規(guī)格的文本。特別指出的是,F(xiàn)reeMarker與Web應(yīng)用框架無關(guān),它同樣可以應(yīng)用在非Web應(yīng)用程序環(huán)境中。
下面我們來看看FreeMarker的模板:(product.ftl)
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href=
"${latestProduct.url}"
>${latestProduct.name}</a>!
</body>
</html>
這個例子是在簡單的HTML中加入了一些由${…}包圍的特定代碼,這些特定代碼就是FreeMarker的指令。
至于user、latestProduct.url和latestProduct.name的具體內(nèi)容則來自于數(shù)據(jù)模型(data model)。數(shù)據(jù)模型由程序員編程來創(chuàng)建,向模板提供變化的信息,這些信息來自于數(shù)據(jù)庫、文件,甚至于在程序中直接生成。
模板設(shè)計者不關(guān)心數(shù)據(jù)從那兒來,只知道使用已經(jīng)建立的數(shù)據(jù)模型。
借助FMPP(FreeMarker PreProcessor)來運行FreeMarker
首先說明的是FreeMarker的運行并不依賴于FMPP。FMPP只是一個FreeMarker的輔助工具,有了它,我們可以快速地調(diào)試FreeMarker輸出結(jié)果,而不需要借助Java編程,這可以大大地減輕美工設(shè)計人員的調(diào)試難度。你可以從: http://fmpp.sourceforge.net/ 得到它。
在使用Freemaker的時候,我們需要下載相關(guān)的程序:
freemarker: http://freemarker.sourceforge.net/
在磁盤上建立相關(guān)的文件夾:
D:/work/src/product.ftl D:/work/out/ D:/work/data/product.tdd D:/work/config.fmpp
我們使用的配置文件(config.fmpp)設(shè)置如下:
sourceRoot: src outputRoot: out logFile: log.fmpp modes: [ copy(common/**/*.*, resource/*.*) execute(*.ftl) ignore(templates/*.*, .project, **/*.xml, xml/*.*, *.js) ] replaceExtensions: [ftl, html] sourceEncoding: gb2312 data: tdd(../data/product.tdd)
注意:"data: tdd(../data/product.tdd)" 指定了模板的數(shù)據(jù)源,TDD是fmpp支持的數(shù)據(jù)格式之一 ,關(guān)于TDD介紹可參閱fmpp文檔,也可參看 TDD 。product.tdd內(nèi)容是這樣的:
{ user: "Big Joe" latestProduct: {url: "products/greenmouse.html" , name: "Green Mouse" } }
現(xiàn)在在dos下執(zhí)行(假設(shè)FMPP安裝在D:/FMPP下):
D:/work/>D:/FMPP/bin/fmpp
最后的輸出結(jié)果是這樣的,存放在文件out/product.html中:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome Big Joe!</h1>
<p>Our latest product:
<a href=
"products/greenmouse.html"
>green mouse</a>!
</body>
</html>
正如FreeMarker文檔中所敘述的,F(xiàn)reeMarker的工作原理就是:
模板+數(shù)據(jù)=輸出!
FreeMarker并不局限于生成html,甚至可以產(chǎn)生java代碼,這僅僅取決于你如何設(shè)計模板而已。
現(xiàn)在有了FMPP這個強大工具,我們接下來可以快速學習FreeMarker的相關(guān)指令。let us go!
在FreeMarker模板中使用的三種基本對象類型:Scalars、Hashes 和Sequences。在解釋這些對象類型之前,我們先來看看數(shù)據(jù)模型。
典型的數(shù)據(jù)模型是樹型結(jié)構(gòu),可以有任意深的層次,比如說:
(root) | +- animals | | | +- mouse | | | | | +- size = "small" | | | | | +- price = 50 | | | +- elephant | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- python | | | +- size = "medium" | | | +- price = 4999
這棵樹上的每一片葉子在FreeMarker中就稱為Scalars,用來存儲單值。Scalars保存的值有兩種類型:字符串(用引號括起,可以是單引 號或雙引號)、數(shù)字(不要用引號將數(shù)字括起,這會作為字符串處理)、日期和boolean值。對scalars的訪問要從root開始,各部分用“.”分 隔,如animals.mouse.price。
樹的每一個分支關(guān)聯(lián)一個唯一的查詢名字,例如“mouse”,“elephant”,這些分支充當了其他對象(size,price)的容器,這種結(jié)構(gòu)則稱為Hashes,參考 Hashes的TDD定義 。
Sequences的作用與Hashes類似,也可以充當其它對象的容器,只是不使用變量名字,而使用數(shù)字索引:
(root) | +- animals | | | +- (1st) | | | | | +- name = "mouse" | | | | | +- size = "small" | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = "elephant" | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = "python" | | | +- size = "medium" | | | +- price = 4999
可以通過animals[0].name來訪問相應(yīng)的Scalars。參考 Sequences的TDD定義
針對上面三種對象類型的操作,可以參看 對象類型的各種操作
模板與指令
除了相關(guān)的文本外,在FreeMarker模板中可以包括下面三種特定部分:
- ${…}:稱為插補(interpolations),F(xiàn)reeMarker會在輸出時用實際值進行替代。
- 指令:也叫FreeMarker標記,與HTML標記類似,但用#開始(有些以@開始,在后面敘述)。
- 注釋:包含在<#-- 和 -->(而不是<!--和-->)之間文本。
控制指令
if指令
if指令與大部分程式語言一樣,也支持<#else if..>,不再贅述。
<# if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <# else > Pythons are not cheaper than elephants today. </# if >
list指令
list指令將遍歷Sequences里的每一個元素。list指令有兩個隱含的特殊變量:
- item_index 該變量將返回元素在Sequences里的索引值。
- item_has_next 該變量是boolean型,false表明該元素是Sequences里的最后一個元素。
<p>We have these animals: <table border=1> <tr><th>Id<th>Name<th>Price <#list animals as being> <tr><td>${being_index+1}<td>${being.name}<td>${being.price} Euros </#list> </table>
上面的模板可以依次列印出三種動物的名字和價格,being_index和being_has_next則是它的特殊變量。
可以用<#break>指令提前結(jié)束list循環(huán)。
switch指令
與其他語言的switch語句類似。
<# 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 >
注意事項
- FTL區(qū)分大小寫,所以list是正確的FTL指令,而List不是;${name}和${NAME}是不同的
- Interpolation只能在文本中使用
- FTL標記不能位于另一個FTL標記內(nèi)部。
- 注釋可以位于FTL標記和Interpolation內(nèi)部。
- 多余的空白字符會在模板輸出時移除
- 可用[#if..]來替代<#if..>,避免于HTML標記混淆。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
