Beetl模闆語言使用指南
什麼是Beetl
Beetl是Bee Template language,Bee譯為忙碌的人,意指忙碌中國的開發人員。目前版本0.6beta,大小約320K
Beetl是國人提供的一款開源免費得模闆語言,作者有10餘年Java開發經驗,曾在國内外著名大公司工作過,根據自己實際使用模闆語言的心得體會而編寫的一款模闆語言,它具有如下特性:
1 非常簡單:它的文法是javascript一個子集,隻有少量的大家熟悉的符号。任何了解java,或者javascript的人,都能快速學會。如果從未用過任何模闆語言,用Beetl是非常很合适的
2 同時支援較為松散的MVC和嚴格的MVC,如果在模闆語言裡嵌入計算表達式,複雜條件表達式,以及函數調用有幹涉業務邏輯嫌疑,你可以禁止使用這些文法。關于這一點,可以參考strictly enforces model-view separation
3 提供一系列其他模闆語言沒有提供的功能,如自定義占位符号,控制語句符号,虛拟屬性,自定義函數,文本處理函數等,它們并不複雜,但有可能解決你在使用别的模闆語言時候遇到的一些不便捷的問題
下載下傳
Beetl能為你做些什麼
作為模闆語言,你可以用于任何适合在MVC的地方。如代碼生成,或者web界面,
因為Beetl是基于antlr實作文法解析的,是以如果你僅僅對antlr感興趣,beetl仍然可以作為你的一個重要參考
關于Beetl性能:
目前實作了runtime版本,适合代碼生成。暫時不适合作為web界面。它本生的是以易讀的方式實作,并未經過優化。然而,即将推出預編譯版本,可以保證有很好的性能
Beetl目前渲染一個7K檔案,内含少量控制語句和占位符,所需要時間是1毫秒,這是在我一個四年前的老機器上跑得,作為代碼生成,你完全無需擔心性能。
beetl(runtime,0.52) | Beetl(runtime,0.6) | Freemarker(2.3.1.8) | Beetl(compiled) | Velocity |
7K(1000次) | 4000毫秒 | 950毫秒 | 900毫秒 | 估計約400毫秒 |
展望Beetl預編譯實作出來後,性能将至少提高2-3倍以上,是以未來能超越Freemaker
關于功能:
http://freemarker.sourceforge.net/fmVsVel.html 是一篇freemaker與velocity功能比較的文章,很幸運Beetl能以簡單易學,更易擴充的方式支援所有功能。
下表是以此文章為基礎做的比較
功能點 | Beetl | Freemarker | velocity |
Number and date support | yes | yes | no |
Internationalization: | Yes,但不支援中文變量名 | yes | no |
Loop handling: | Yes,better | yes | no |
Array handling on the template language level | yes | yes | no |
Macros | Yes | Yes | no |
Name-spaces: | No | yes | no |
Java-independent string, list, and map manipulations with built-in functions/operators: | yes | yes | no |
Expose typos and other mistakes in template | Yes,better | yes | no |
Advanced rendering control: | yes | yes | no |
Literals: | yes | yes | no |
Advanced white-space removal | No ,不明白為啥有此需求 | yes | no |
Integration with other technologies: | yes | yes | yes |
Powerful XML transformation capabilities: | no | yes | no |
Advanced template metaprogramming: | No,不明白為啥有此需求 | yes | no |
function | No,覺得模闆不需要 | yes | No |
自定義控制語句 | yes | no | no |
自定義占位符号 | yes | no | no |
嚴格MVC控制 | yes | no | no |
虛拟屬性 | yes | no | no |
文本處理函數 | yes | no | no |
自定以錯誤處理Hanlder | yes | no | no |
基本用法
Hello Beetl
package org.bee.tl.samples; import java.io.IOException; import org.bee.tl.core.BeeTemplate; public class HelloBeetl { public static void main(String[] args)throws IOException { Template template =new BeeTemplate("Hello,$name$");// 1 template.set("name","Beetl");//2 String result = template.getTextAsString();//3 System.out.println(result); } } |
1用于BeeTemplate建立一個模闆,此時使用的是一個字元串輸入,輸入也可以是java.io.File或者java.io.reader.對于beetl來說,如果輸入是檔案,那将會緩存中間的解析結果而大幅度提升性能
2定義變量,set方法允許字元串,對象作為參數,如果需要引用對象的屬性,則用小數點,如$user.name$,如果屬性是個List集合,可以用[索引],如$user.friends[0]$,如果屬性是Map集合,
使用[key],key為任何對象,如$books[‘thinking in java’].author$
3調用template.getTextAsString() 或者template.getText(OutputStream os)都可以獲得模闆渲染的結果
控制語句和占位符号
Beetl預設情況下,采用#:作為控制語句開始,回車作為控制語句結束
#:for(user in userList){ hello,$user.name$ #:} |
預設情況下,占位符号使用$作為開始和結尾占位符号
$users[index]$ |
然而,Beetl支援自定義控制語句和占位符号,以适應不同類型模闆檔案
public static void main(String[] args) { String input = ”…..” BeeTemplate template =new BeeTemplate(input); template.setStatementStart("<%"); template.setStatementEnd("%>"); template.setPlaceholderStart("~"); template.setPlaceholderStart("~"); template.getTextAsString(); } |
此代碼可以解析如下模闆檔案
<% var temp=”lijz”; %> Hello ~temp~ ! |
建議:控制語句和占位符号最好不要影響原有檔案,可以使用<!--: -->作為XML模闆檔案控制語句,使用#:作為通常shell腳本,配置檔案的控制語句
API接口
Beetl 主要的接口Template 和 類 GroupTemplate.
Template 實作類分為BeeTemplate 和 CompiledBeeTemplate,前者用于解釋執行模闆,适合代碼生成或者開發階段使用,後者是預編譯成class,适合web架構或者生産模式使用。
org.bee.tl.core.Template 常用API | |
public void set(String name, Object o) | 設定模闆變量 |
public void getText(OutputStream os) | 渲染模闆到os |
public void getText(Writer w) | 渲染模闆到wirter |
public String getTextAsString() | 渲染模闆,結果作為String傳回 |
public void makeStrict(boolean isTrict) | 是否使用嚴格MVC |
org.bee.tl.core.Template 進階API (同org.bee.tl.core..GroupTemlate) | |
public void setPlaceholderStart(String placeholderStart) | 設定占位符好開始标記,預設是$ |
public void setPlaceholderEnd(String placeholderEnd) | 設定占位符好結束标記,預設是$ |
public void setStatementStart(String statementStart) | 設定控制語句開始标記,預設是#: |
public void setStatementEnd(String statementEnd) ; | 設定控制語句結束标記,預設是null,也就是檔案回車換行符号 |
public void registerFunction(String name,Function fn); | 為Beetl注冊一個自定義函數,參考進階用法 |
public void registerFormat(String name,Format format); | 為Beetl建立一個格式化函數,參考進階用法 |
public void registerTextProcess(String name,TextPorcessFunction process); | 為Beetl建立一個文本處理函數,參考進階用法 |
public void registerVirtualAttributeEval(VirtualAttributeEval e); | 為某對象設定一個虛拟屬性,參考進階用法 |
Beetl 不推薦直接調用進階API,在一個真正的系統裡,首先通過GroupTemlate設定好模闆所有屬性,然後調用 GroupTemlate.getTetmplate來擷取Template,如下代碼
package org.bee.tl.samples; import org.bee.tl.core.GroupTemplate; public class GroupTemplateUtil { static GroupTemplate group = new GroupTemplate(); static {| group.setPlaceholderStart("$"); group.setPlaceholderEnd("$"); group.setStatementStart("#:"); group.setStatementEnd(null); group.makeStrict(true); } public static GroupTemplate getGroup (){ return group; } |
org.bee.tl.core.GroupTemplate 常用API | |
public GroupTemplate() | 構造一個GroupTemplate |
public GroupTemplate(File root) | 構造一個GroupTemplate,且制定模闆檔案跟目錄,此目錄下的模闆檔案都将編譯成class,(前提是isProduct = true |
public Template getStringTemplate(String input) | 得到一個BeeTemplate |
public Template getReaderTemplate(Reader reader) | 得到一個BeeTemplate,輸入是Reader |
public Template getFileTemplate(String child) | 如果isProudct=true,得到一個CompiledBeeTemplate模闆,否則得到一個BeeTemplate |
public void setProduct(boolean isProduct) | 訓示Beetl運作在開發模式還是生産模式 |
注意:要真正獲得預編譯支援以用于Web或者高性能項目, 隻有通過GroupTemplate(File root) 構造的GroupTemplate ,且sProudct=true ,
然而,目前暫時不支援預編譯版本
定義變量
Beetl允許定義變量,準确的說,允許定義臨時變量,如下所示
#:var name=’lijz’,loopCount=100+other ,girlName; |
關鍵字var是必須得,這點不同于javascript
Beelt中得變量同javascript一樣,有自己的作用域,如下模闆輸出為”lucy”
#:var name=’lijz’,i=1; #:if(i>=1){ #:var name=’lucy’; Hello,$name$ #:} |
變量命名規則同javascript或者java,但不允許以倆個下劃線開頭"__",這是因為以此開頭的多為Beetl内部的一些臨時變量
算術表達式
Beetl支援類似javascript的算術表達式和條件表達式,如+ - * / % 以及(),如下例子
#:var a=1,b=2,c=3; the result is $(a+b)*c-0.75$ |
邏輯表達式
Beetl支援類似Javascript,java的條件表達式 如>, <, == ,!=,>= , <= 以及 !,如下例子
#:var a=1,b=2,c=3;if((b-c)>=1){ Hello big! #:}else{ :( ,small! #:} |
循環語句
Beetl 支援for in 循環格式,以及break,continue,return (實際上可以出現在任何地方),如下例子
//java代碼 tempalte.set("userList",userList); //模闆 總共 $userList.~size$ #:for(user in userList){ $user.~index$ . Welcome $user.name$! #:} |
如果循環中,需要引用目前索引和總數,可以分别使用虛拟屬性index,size
條件語句
Beetl隻支援同javascript,java一樣的if 語句,不支援switch. 如下例子
#:var isGirl = true; #:if(isGir){ 姑娘,你好 #:}else{ 小夥子,你好 #:} |
函數調用
Beetl内置了少量實用函數,可以在Beetl任何地方調用,一般情況是在占位符裡調用。
如下例子是調用NVL函數,判斷如果變量為不為null,則輸出變量,如果為null,則輸出預設值
//java代碼 template.set("name",service.getName(id)); //模闆 The name is $nvl(name,"defaultValue")$ |
如下例子casef,判斷變量與哪個值比對,便顯示響應的值
//java代碼 template.set("score",3); //模闆 The name is $casef(score,3,"Good",2 ,"so-so",1 ,"bad","error score")$ |
Beetl允許使用者自定義函數以适合特定領域使用,請參考進階用法。也歡迎有人把他認為能公用的函數發給我,我将作為核心函數放入beetl裡
格式化
幾乎所有的模闆語言都支援格式化,Beetl也不列外,如下例子Beetl提供的内置日期格式
#:var date = now(); Today is $date,df="yyyy-MM-dd"$. Today is $date,df$ |
如果沒有為格式化函數輸入參數,則使用預設值,df格式化函數預設值是local
Beetl允許使用者自定義格式化函數以适合特定領域,請參考進階使用者,也歡迎有人把他認為能公用的格式化函數發給我,我将作為核心函數放入beetl裡
錯誤處理
Beetl預設情況使用 org.bee.tl.core.DefaultErrorHandler 來處理文法解析錯誤和運作時刻的錯誤,預設情況下,會顯示行号,錯誤原因,以及錯誤的關鍵字
如下所示
BeeTemplate t = new BeeTemplate("#:if(!isGirl){var c=1;}"); t.makeStrict(true); t.set("isGirl", false); t.getTextAsString() ; 會導緻如下編譯錯誤 STRICK_MVC 位于1行,符号 var 1|#:if(!isGirl){var c=1;} |
其他瑣碎功能
對齊: 我發現别的模闆語言要是做到對齊,非常困難,Beetl你完全不用擔心,比如velocty,stringtemlate,freemarker例子都出現了不對齊的情況,影響了美觀,Beetl完全無需擔心輸出對齊
包含其他模闆檔案:在Beetl中,這不是一個特殊的功能,通過調用函數includeFT,或者includeST都可以實作,前者是包含一個檔案模闆,後者是将一個string模闆作為輸入。詳細使用請參考進階用法
Escape:可以使用/ 做escape符号,如hello,it's $money$/$, 或者Hello,it's $money+"/$"$
空值政策: 在輸出一個變量的時候,如果為null,是應該抛出異常還是僅僅忽略,列印出預設值,Beetl相對于其他模闆語言來說,控制的更為精細,如下代碼
#:var NULL='N/A';var NULL_POLICY=1; $u.name$ |
第一行訓示空值情況下僅僅輸出預設值,此時NULL_POLICY=1 表示不抛出異常,而僅僅輸出預設值,0為預設情況,即抛出異常,停止渲染
你可以在Beetl中任何一處重新設定這些值以滿足特定的需求。
文本處理函數:文本處理函數允許你将模闆檔案中的一段檔案内容作為輸入,經過函數操作,變成特定的輸出,如下内置的replaceProperties
#:replaceProperties(ip,port){ Server_ip= 127.0.0.1 Server_port= 8080 #:} #:if(isProduct) { delNext(){ Debug_para1=..... Debug_para2=...... #:} |
如果在java代碼中,tempalte.set("ip",targetIP),template.set("port",targetPort);
則模闆檔案裡等于号後的字元串将被以此替換.
如果在java代碼中,template.set("isProduct",true),則所有debug參數都将被删除。關于文本處理函數概念,請參考進階用法
進階用法
自定義函數
Beetl允許提供自定義函數以适合特定業務需求,自定義函數需要實作org.bee.tl.core.Function。如下定義了一個now函數僅僅傳回一個java.util.Date執行個體
public class DateFunction implements Function { public Object call(Object... paras) { return new Date(); } public static void main(String[] args) throws IOException{ GroupTemplate group = new GroupTemplate(); group.registerFunction("now", new DateFunction()); Template t = group.getStringTemplate("today is $now()$"); System.out.println(t.getTextAsString()); } } |
格式化函數
Beetl允許提供自定義格式化函數,用于格式化輸出。 格式化函數需要實作org.bee.tl.core.Format
public class DateFormat extends Format { public Object format(Object data,String pattern){ SimpleDateFormat sdf = null; if(pattern==null){ sdf = new SimpleDateFormat(); }else{ sdf = new SimpleDateFormat(pattern); } return sdf.format(data); } public static void main(String[] args)throws IOException { GroupTemplate group = new GroupTemplate(); group.registerFunction("now", new DateFunction()); group.registerFormat("df", new DateFormat()); Template t = group.getStringTemplate("today is $now(),df=’yyyy-MM-dd’$"); System.out.println(t.getTextAsString()); } } |
嚴格MVC控制
如果設定了嚴格MVC,則以下文法将不在模闆檔案裡允許,否則将報出STRICK_MVC 錯誤
l 定義變量,為變量指派
l 算術表達式
l 除了隻允許布爾以外,不允許邏輯表達式
l 方法調用
虛拟屬性
無需為java對象定義額外的屬性用于輔助顯示,虛拟屬性可以輕易做到,如Beetl為java.util.Collection 定義的一個虛拟屬性size,用于表示集合大小
group.registerVirtualAttributeEval(new VirtualAttributeEval(){ public Object eval(Object o,String attributeName,Context ctx){ if(attributeName.equals("size")){ return ((Collection)o).size(); }else{ throw new IllegalArgumentException(); } } public boolean isSuppoert(Class c,String attributeName){ if(Collection.class.isAssignableFrom(c)&&attributeName.equals("size")){ return true; }else{ return false; } } }); |
這樣,是以Collection子類都有虛拟屬性size。$userList.~size$ 輸出userList集合長度
實作虛拟屬性,必須實作接口倆個方法,一個是isSupport,這讓Beetl用于找到VirtualAttributeEval,eval方法用于計算虛拟屬性
文本處理函數
所謂文本處理函數,即允許處理模闆檔案裡的一塊内容。如下{}的内容在beetl運作的時候将會被删除
#:del(){ This content will be deleted #:} |
自定義文本處理函數必須實作org.bee.tl.core.TextPorcessFunction,需要實作requriedInput,用于告訴Beetl,是否需要先渲染文本體。
getOutput 用于傳回文本處理函數的結果
如下是Beetl提供的内置的del文本處理函數實作
public class DeleteFunction extends TextPorcessFunction{ public String getOutput(){ return ""; } @Override public boolean requriedInput(){ return false; } } |
可以通過父類屬性args,擷取輸入參數,詳細可以參考API
自定義錯誤處理
<!--EndFragment-->