TinyTemplate(Velocity Plus版)即將火熱推出~~~

原本是沒有本身寫一個模板引擎的計劃的,由於按個人理解,一直認識這種「語言」級的引擎,難度是很是大的。總感受本身的水平不夠,所以不敢有這個念頭。直到大量使用Velocty的時候,碰到velocty諸多盡如人意的地方,可是又無能爲力,退回到JSP吧,又心不有甘。因而就指望着尋找一種語法結構接近velocty,可是又沒有Velocity這些不方便之處的模板語言。因而進到一個模板語言羣,一羣大佬們個個至少是一個模板語言的做者,因而做者在裏面表達了本身的指望,大佬們都介紹了本身的模板引擎,因而做者一個接一個的看源碼,看文檔。說實際,看文檔,感受都很是不錯,都有本身的特點,看語法也都不錯,除了一部分本身特別關注的點沒有以外,其部分都很是不錯了。可是距離本身的訴求仍是有差距,怎麼辦呢?因而就準備找一個最接近的模板引擎來進行必定的擴展,挑來挑去就挑中了jetbrick這個模板語言(在此對Jetbrick致以強烈的衷心的感謝!!)。css

之因此挑這個呢,是由於如下幾個緣由:html

  1. Antlr語言文件編寫很是清晰,對於我這種Antlr盲來講,也能夠看得懂,甚至能夠照葫蘆畫瓢修改修改,這個很是重要,在後期做者進行了至關的語法改進,這個方面有極度體現java

  2. 代碼質量較好,使用sonar進行進行分析,給的結果都仍是至關不錯的,在做者看過的全部的模板語言中,算上成之選git

  3. 語法結構與Velocity的很是接近,這點對我也很是重要,由於個人想法就是velocity語法有至關的接受度,與Velocity語法接近,velocity的一些使用者能夠方便的進行切換express

  4. 測試用例比較完善,當時也就是這麼一看,可是最後Tiny模板引擎完成以後,利用其測試用例進行測試發現了好幾個BUG,說明仍是很是有效果的json

因而下載了源碼,初端詳仍是不錯的,可是在實如今幾點和筆記訴求有差距:api

第一我但願是弱類型,jetbrick是強類型,性能是有提升可是開發過程會比較不方便。數組

另外因爲jetbrick做者指望在編譯器進行強類型推測,所以致使運行期的內容與編譯期的內容有比較強的耦合。框架

另外有一些語言特性,屬於我的愛好上的緣由,也有一些差別,所以就決定本身編寫一個。函數

語法規範

爲了更好的說明Tiny的語法規範,所以全程對比Velocity

說明,<>中的內容表示必須有至少一個,[]中的內容表示能夠有能夠沒有。

References

表達式

${表達式}

表達式是指最後的運算結果是一個值,表達式中可使用變量

=>與Velocity區別,這裏大括號必須有,不能省略,「-」號不容許出現

${a+b-c+d}

${"abc"+1}

${user.name}

${user.items[1].count+3}

${user.func(1,2,3,4)+map.def+map["aa"]}

變量

<a->[_a-zA-z0-9]

=>與Velocity區別,「-」號不容許出現

示例:

合法

  • abc

  • ab_c

  • Ab9_

非法

  • 9bc

  • _bc

  • a-b

屬性值

屬性語法與變量名同樣

區別大括號必須有,「-」號不能夠有

屬性值實際上也是個表達式,所以這麼寫也是能夠的

${a.("aa"+bb)},若是bb的值爲3,則等同於${a.aa3},等同於a."aa3"

指令

#set - 賦值指令

Format:

#set ( ref = [ ", ' ]arg[ ", ' ] )

示例

#{set}不被支持

變量名前面不能夠加$

#set(aa=1)

#set(aa=2,b=2,c=aa+2,d=func("info"))

#set(aa=[aa,"bb",2,3,4]

#set(aa={"aa":1,bb:2,aa.bb.func()+3:5}

#if/#elseif/#else - 判斷語句

格式:

#if( [condition] ) [output] [ #elseif( [condition] ) [output] ]* [ # [ { ] else [ } ] [output] ] # [ { ] end [ } ]

用法:

#if(aa)

#end

#if(aa||bb)

#end

這裏便可以是邏輯表達式,也能夠是非邏輯表達式

狀況以下:

若是是null,則false

若是是boolean值,看true/false

若是是String,看長度>0

若是是Collection,看Size>0

若是是Iterator看hasNext

若是是數組,看長度>0

若是是Enumerator,看hasMoreElements

若是是Map看size

其它狀況,就返回true

下面全部的邏輯表達式都支持

Operator Name  
Symbol    
Alternative Symbol    
Example

Equals Number  
==    
eq    
#if( $foo == 42 )

Equals String  
==    
eq    
#if( $foo == "bar" )

Object Equivalence  
==    
eq    
#if( $foo == $bar )

Not Equals  
!=    
ne    
#if( $foo != $bar )

Greater Than  
>    
gt    
#if( $foo > 42 )

Less Than  
<    
lt    
#if( $foo < 42 )

Greater Than or Equal To  
>=    
ge    
#if( $foo >= 42 )

Less Than or Equal To  
<=    
le    
#if( $foo <= 42 )

Boolean NOT  
!    
not    
#if( !$foo )

Notes:

  1. ==用的是equals

  2. 能夠用下面的方式來避免與顯示內容分不開

#if(foo == bar)it's true!#{else}it's not!#end</li>

注意:與Velocity區別:變量名前面不要加「$」符號

#for - for循環指令

Format:

# for(varName : collection) 顯示內容1 [#[{]else[}] ]&#160; 顯示內容2 # [ { ] end [ } ]

表示對集合進行循環,執行顯示內容1,若是集合爲空,則執行顯示內容2

注意:與Velocity區別:增了了#else指令

能夠是collection的內容:

數組、集合、Iterator,Enumeration,Map,對象,甚至null

若是不是集合對象,只是一個普通對象,就只循環次,這比較適合於有時候會返回列表,有時候會返回一個對象的狀況,就避免了增長複雜的判斷。

#include - 包含指令

Format:

#include(expression[,{aa:1,bb:2}])

示例:

#include("/aa/bb/cc.vm")

#include("/aa/bb/cc.vm")

與Velocity的區別:用於把另外的頁面在當前位置進行渲染,後面只能加一個Map用來傳遞參數

#parse:指令已經沒有意義被取消
#stop - Stops the template engine

Format:

#stop[(expresson)]

Usage:

#if(aa==bb)

#stop

#end

等價於

#stop(aa==bb)

#break - Stops the current directive

Format:

#break[(expresson)]

Usage:

#if(aa==bb)

#break

#end

等價於

#break(aa==bb)

#continue[(expresson)]

Usage:

#if(aa==bb)

#continue

#end

等價於

#continue(aa==bb)

#evaluate - Dynamically evaluates a string or reference因爲難用被取消,且用處過小被取消

增長指令#[@]call

#call("aa"+"bb",1,2)

等同於

#aabb(1,2)

#call(format("Sys%sMdl%s",1,2),1,2)

等同於

#Sys1Mdl2(1,2)

#@call("aa"+"bb",1,2)

...

#end

等同於

#@aabb(1,2)

...

#end

#@call(format("Sys%sMdl%s",1,2),1,2)

...

#end

等同於

#@Sys1Mdl2(1,2

...

#end

另外支持命名傳遞,詳見宏調用

#define - 因爲雞肋被取消,調用者中的全部變量對於被調用者均可見,再也不須要顯式傳遞
#macro - 定義宏

Format:

# macro macroName( arg1 [, arg2,arg3 ... argn ] ) [ VM VTL code... ] # [ { ] end [ } ]

與 Velocity不一樣:macroName由括號裏放在了括號外面,避免與參數混一塊兒,參數之間必須用逗號隔開

調用宏有兩種方式

#vmname( arg1,arg2 )

#@vmname(arg1,args)

....

#end

與Velocity不一樣:支持命名調用:

好比下面的方式; #vmname(arg2=3),也能夠混用:#vmname(1,2,arg5=3,arg4=4)

註釋:

##單行註釋

#-- ... --#&#160; #* ... *#,兩種格式支持,是考慮到在<!-- -->的時候,改爲#-- --#更方便

非解析標記,下面的內容會原樣輸出

#[[
This has invalid syntax that would normally need "poor man's escaping" like:

    • #define()

  • ${blah

]]#


新增長內容:i18n支持:

$${aaa.bbb.ccc}

表示顯示aaa.bbb.ccc對應的國際化內容

固然,還有強大的佈局(頁面繼承),容易的使用(會vm的到如今已經會用),方便的擴展(很是容易擴展),微小的體量(引擎只有2000行代碼),還想要什麼,能夠盡情提出。

新增內容:Java對象方法擴展,即在不修改原類的狀況下,對java類添加

好比能夠爲String增長bold函數,經過下面的方式來進行加粗

${「悠然是個好同志」.bold()}

也能夠給 Object增長toJson,toXml等方法,從而直接用下面的方式輸出json或xml:

${user.toJson()},${user.toXml()}

固然,如今還有一點計劃中的特性沒有實現,那就是裝飾方式的佈局方式,可能有些同窗不瞭解,那就先留點懸念吧。

下面看看實際演練:

<!DOCTYPE html>
<html>
<head>
    <title>StockModel - Httl</title>
    <meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}"/>

    <style type="text/css">
        body {
            color: #333333;
            line-height: 150%;
        }

        td {
            text-align: center;
        }

        thead {
            font-weight: bold;
            background-color: #C8FBAF;
        }

        .odd {
            background-color: #F3DEFB;
        }

        .even {
            background-color: #EFFFF8;
        }
    </style>
</head>
<body>
<h1>StockModel - jetbrick-template</h1>
<table>
    <thead>
    <tr>
        <th>#</th>
        <th>id</th>
        <th>code</th>
        <th>name</th>
        <th>price</th>
        <th>range</th>
        <th>amount</th>
        <th>gravity</th>
    </tr>
    </thead>
    <tbody>
    #for(item : items)
    <tr class="${itemFor.index % 2 == 1 ? "even" : "odd"}">
        <td>${itemFor.index}</td>
        <td>${item.id}</td>
        <td>${item.code}</td>
        <td style="text-align: left;">${item.name}</td>
        <td>${item.price}</td>
        <td style="color: ${item.range>=10?'red':'blue'};">${item.range}%</td>
        <td>${item.amount}</td>
        <td style="color: ${item.gravity>=20?'red':'blue'};">${item.gravity}%</td>
    </tr>
    #end
    </tbody>
</table>
</body>
</html>

下面是渲染結果:

<!DOCTYPE html>
<html>
<head>
    <title>StockModel - Httl</title>
    <meta http-equiv="Content-Type" content="text/html; charset=gbk"/>

    <style type="text/css">
        body {
            color: #333333;
            line-height: 150%;
        }

        td {
            text-align: center;
        }

        thead {
            font-weight: bold;
            background-color: #C8FBAF;
        }

        .odd {
            background-color: #F3DEFB;
        }

        .even {
            background-color: #EFFFF8;
        }
    </style>
</head>
<body>
<h1>StockModel - jetbrick-template</h1>
<table>
    <thead>
    <tr>
        <th>#</th>
        <th>id</th>
        <th>code</th>
        <th>name</th>
        <th>price</th>
        <th>range</th>
        <th>amount</th>
        <th>gravity</th>
    </tr>
    </thead>
    <tbody>
    
    <tr class="even">
        <td>1</td>
        <td>1</td>
        <td>600663</td>
        <td style="text-align: left;">Company 01</td>
        <td>20.55</td>
        <td style="color: red;">10.01%</td>
        <td>2.13 HM</td>
        <td style="color: red;">24.29%</td>
    </tr>
    
    <tr class="odd">
        <td>2</td>
        <td>2</td>
        <td>600822</td>
        <td style="text-align: left;">Company 02</td>
        <td>14.69</td>
        <td style="color: red;">10.04%</td>
        <td>1.56 HM</td>
        <td style="color: red;">36.79%</td>
    </tr>    
    </tbody>
</table>
</body>

補充一下,上面原本是有20行數據的,爲了節省空間,給刪除了18行。

下面是程序代碼:

    public static void main(String[] args) throws TemplateException {
        TemplateEngine engine = new TemplateEngineDefault();
        TemplateContext context=new TemplateContextDefault();
        context.put("outputEncoding","GBK");
        context.put("items", StockModel.dummyItems());
        engine.addTemplateLoader(new FileObjectTemplateLoader("jetSample", "D:\\git\\ebm\\src\\main\\resources\\templates"));
        engine.renderTemplate("/tiny.html",context,new OutputStreamWriter(System.out));
    }

固然了,可能你們對性能很是感興趣。

Tiny框架的性能比Beetl-1.26稍微落後一點點,可是明顯比Velocity和FreeMarker是快多了。

與前面幾個引擎比較,性能差別主要在:

1.強類型與弱類型方面的差別,TinyTemplate採用的是弱類型,而一些模板引擎採用的是強類型。

2.其它引擎都已經通過了長時間的優化,而 TinyTemplate只是剛二通過不到一週的初始期。經過後面的一些優化,他將有必定的提高(可是達不到Jetbrick這個程度)

這天這個只是開胃菜,親們耐心等待個人正式發佈吧。

附錄:

TinyTemplate歷史三天編寫,代碼行數量截止發稿爲在3410,預計完稿後,在3700行左右。

JetBrick爲1.3萬+

Beetl爲1.7萬+

對於Velocity用戶來講,遷移很是容易。

原本但願velocity升級2.0的可是實在等不到,所以只好本身動手升級了。

凡有好的意見、建議、需求的,所有采納並快速實現,在此提早致以感謝!

相關文章
相關標籤/搜索