Web前端:FreeMarker技術指南
一、什麼是模板引擎,為什麼要用模板引擎
在B/S程式設計中,常常有美工和程式設計師二個角色,他們具有不同專業技能:美工專注於表現——建立頁面、風格、佈局、效果等等可視元素;而程式設計師則忙於建立程式的商業流程,生成設計頁面要顯示的資料等等。
很多時候,要顯示的資料在設計的時候並不存在,它們一般是在執行時由程式產生的,比如執行“價格不高於800NT的USB Disk”查詢的返回結果。這種技術需求產生了JSP等Scriptlet,JSP十分強大,但是也常常被濫用,並導致一些不良的後果
- 將邏輯和表現混合在一起。
- 破壞了美工和程式設計師職責的正常分解。
- 使JSP頁面難以閱讀和維護。
模板引擎就是為了解決上面的問題而產生的。在設計
模板和嵌入JSP的HTML是不同的,模板指令只有很有限的程式設計能力,可以避免混入商業邏輯。
二、Java常用的模板引擎 Velocity vs FreeMarker
1.Velocity 比 FreeMarker簡單好學
2.FreeMarker 比 Velocity功能強大
三、一個簡單的FreeMarkerDemo
1.匯入Jar包:
FreeMarker需要freemarker-2.3.19.jar
2.編寫模板檔案
FreeMarker的模板檔案的字尾名是ftl。這裡是我寫的一個Example.ftl,我把它放在WebRoot下的Template資料夾下。
<html> <head> <title>Example</title> </head> <body > <h1>大家好,我的名字叫${name},我家住在${address},我今年${age}歲了!</h1> </body> </html>
3.模板的解析
模板需要被解析之後才能生成最終的檔案,
ExampleResolution.java
publicclass ExampleResolution { publicvoid resolution(){ Writer out = null; Configuration cfg = new Configuration(); cfg.setServletContextForTemp<wbr>lateLoading(ServletActionContext.getServletContext(),"TemplateFiles"); cfg.setDefaultEncoding("UTF-8"); Map root = newHashMap(); root.put("name","李鑫龍"); root.put("address","合肥市望江西路666號"); root.put("age", 23); try { Template template = cfg.getTemplate("Example.ftl"); String path = ServletActionContext.getServletContext().getRealPath("/"); File file = new File(path +"example.html"); out = new BufferedWriter(new OutputStreamWriter(newFileOutputStream(file))); template.process(root, out); } catch (IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); }finally{ try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } }</wbr>
4.Action配置
publicclass ServiceActionimplements Action { @Override public String execute()throws Exception { ExampleResolution er = new ExampleResolution(); er.resolution(); return Action.SUCCESS; } }
5.struts.xml配置
<packagename="default" namespace="/"extends="struts-default,json-default"> <action name="example"class="com.lubby.action.ServiceAction"> <resulttype="redirect">/example.html</result> </action> </package>
6.效果顯示
</html> <head> <title>Example</title> </head> <body > <h1>大家好,我的名字叫李鑫龍,我家住在合肥市望江西路666號,我今年23歲了!</h1> </body> </html>
四、FreeMarker的資料模型
資料模型是樹型結構,可以任意複雜和深層次,如下面的例子:
(root) | +- animals | | | +- mouse | | | | | +-size = "small" | | | | | +-price = 50 | | | +- elephant | | | | | +-size = "large" | | | | | +-price = 5000 | | | +- python | | | +- size = "medium" | | | +- price = 4999 | +- test ="It is a test" | +- whatnot | +-because = "don't know"
類似於目錄的變數稱為hashes,包含儲存下級變數的唯一的查詢名字類似於檔案的變數稱為scalars,儲存單值
scalars儲存的值有兩種型別:字串(用引號括起,可以是單引號或雙引號)和數字(不要用引號將數字括起,這會作為字串處理)
對scalars的訪問從root開始,各部分用“.”分隔,如animals.mouse.price
另外一種變數是sequences,和hashes類似,只是不使用變數名字,而使用數字索引,如下面的例子:
(root) | +- animals | | | +- (1st) | | | | | +-name = "mouse" | | | | | +-size = "small" | | | | | +-price = 50 | | | +- (2nd) | | | | | +-name = "elephant" | | | | | +-size = "large" | | | | | +-price = 5000 | | | +- (3rd) | | | +- name = "python" | | | +- size = "medium" | | | +- price = 4999 | +- whatnot | +- fruits | +- (1st)= "orange" | +- (2nd)= "banana"
這種對scalars的訪問使用索引,如animals[0].name 這種對scalars的訪問使用索引,如animals[0].name
五、模板的常用指令
在FreeMarker模板中可以包括下面幾個特定部分:
1.${…}:稱為interpolations,FreeMarker會在輸出時用實際值進行替代。
1.1 ${name}可以取得root中key為name的value。
1.2 ${person.name}可以取得成員變數為person的name屬性
2.<#…>:FTL標記(FreeMarker模板語言標記):類似於HTML標記,為了與HTML標記區分
3.<@>:巨集,自定義標籤
4.註釋:包含在<#--和-->(而不是<!--和-->)之間
六.常用的FTL標記:
1、if指令:用於判斷的指令
<#if (2>3)>
二比三大
<#else>
三比二大
</#if>
2、list指令:用來遍歷Map和List的
2.1遍歷List的資料
<#list arrList as item>
${item}
</#list>
2.2遍歷Map的資料
<#listmyMap?keys as item>
${item}-à${myMap[item]}
</#list>
2.3 item_has_next:判斷list是否還有值,
<#listarrList as item>
<#if item_has_next>more,
<#else>end.
</#if>
</#list>
2.4<#break />指令可以跳出迴圈
<#listarrList as item>
<#if!item_has_nex>end. <#break />
</#if>
more,
</#list>
3、include指令:用來引入另一個另一個ftl模板或者html頁面
<#include“TemplateFiles/example.ftl”>
4、assign指令:用於為該模板頁面建立或替換一個頂層變數
變數為String <#assign address=”上海”>
我家住在${address}
結果:我家住在上海
變數為map: <#assign person={"name":"Tom","age":20,"address":"上海"} >
我的名字叫${person.name},我今年${person.age},我家住在${person.address}
結果:我的名字叫Tom,我今年20,我家住在上海
5、import指令:用於匯入FreeMarker模板中的所有變數,並將該變數放置在指定的Map物件中。
<#import "/libs/mylib.ftl"as my>
6.判斷為空: FreeMarker預設是不允許值為空或者值不存在的,否則一定會報錯。所以我們需要一些方法來判斷是否為空或者是否存在
方法一:<h1>Welcome${user!"Anonymous"}!</h1>
當user為空或者不存在會預設為Anonymous.
${user!}這個當user不存在或為空時候,不會報錯,也不會輸出。
方法二:<#if name??>name is exist</#if>
這裡會先判斷,若name為空或不存在則不會執行if內部的,也不會報錯
七、內建函式:
使用方法類似於訪問雜湊的子變數,只是使用?代替.例如:${test?upper_case?html}常用的內建函式列舉如下:
?html: html字元轉義
?cap_first: 字串的第一個字母變為大寫形式
?lower_case :字串的小寫形式
?upper_case :字串的大寫形式
?trim:去掉字串首尾的空格
?substring:截字串
?lenth: 取長度
?size: 序列中元素的個數
?int : 數字的整數部分(比如- 1.9?int 就是- 1)
?replace:字串替換
一些示例:
${username?[0,10]}
${appHtml?replace('<@person.component/>', "AK47test")}
八、FreeMarker macro(巨集)的使用
1.example1.ftl 設定巨集
<#macroname >
我的名字叫做${name}!
</#macro>
2.example2.ftl 呼叫example1.ftl的巨集
<#inclue“example1.ftl”>
<#macroname=”王曉樂”></#macro>
最終可以在example2.ftl模板生成的頁面中得到
我的名字叫做王曉樂!
3.關於關於巢狀指令<#nested>
<#macrogreet>
<#nested>
<#nested>
</#macro>
呼叫:<@greet>hello!</@greet>
結果: hello!
hello!
九、利用macro簡單封裝的jqGrid的使用方法
1.macro名和引數的呼叫Demo
<@myjqgrid url="jqgridtest.action" colNameList=["來電號碼","業務型別","編號"] colModelList=[["customer","string"],["bussiness","string"],["id","int"]] caption="jqgrid測試三" width="500" height="250" divId="jqgridOne" />
2.引數的含義
url:請求的action的URL
colNameList:jqGrid表所需要顯示的欄位
colModelList:jqGrid中colModelList中的欄位的英文名,和排序的型別
caption:表格的標題名
width:長度
height:高度
divId:div的id名
十、利用macro簡單封裝的highcharts的使用方法
1.macro名和引數的呼叫Demo
<@highcharts divId="container1" type="column" title="2012年氣溫變化表一" subtitle="合肥氣象局提供" yTitle="溫度 (°C)" function=" return'<b>'+ this.series.name +'</b><br/>'+ this.x +': '+ this.y+'°C';" width="500" height="300"/>
2.引數的含義
divId:div的id名
type:圖表的型別 / line直線 / pie餅狀 / bar橫向條狀 / column柱狀圖
title:圖表的標題
subtitle:圖表的副標題
yTitle:縱座標的標題
function:當滑鼠移到節點時,返回的資訊
width:寬度
height:高度