天天看點

Beetl 0.6beta 釋出,歡迎使用

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-->