原本是沒有本身寫一個模板引擎的計劃的,由於按個人理解,一直認識這種「語言」級的引擎,難度是很是大的。總感受本身的水平不夠,所以不敢有這個念頭。直到大量使用Velocty的時候,碰到velocty諸多盡如人意的地方,可是又無能爲力,退回到JSP吧,又心不有甘。因而就指望着尋找一種語法結構接近velocty,可是又沒有Velocity這些不方便之處的模板語言。因而進到一個模板語言羣,一羣大佬們個個至少是一個模板語言的做者,因而做者在裏面表達了本身的指望,大佬們都介紹了本身的模板引擎,因而做者一個接一個的看源碼,看文檔。說實際,看文檔,感受都很是不錯,都有本身的特點,看語法也都不錯,除了一部分本身特別關注的點沒有以外,其部分都很是不錯了。可是距離本身的訴求仍是有差距,怎麼辦呢?因而就準備找一個最接近的模板引擎來進行必定的擴展,挑來挑去就挑中了jetbrick這個模板語言(在此對Jetbrick致以強烈的衷心的感謝!!)。css 之因此挑這個呢,是由於如下幾個緣由:html
因而下載了源碼,初端詳仍是不錯的,可是在實如今幾點和筆記訴求有差距:api 第一我但願是弱類型,jetbrick是強類型,性能是有提升可是開發過程會比較不方便。數組 另外因爲jetbrick做者指望在編譯器進行強類型推測,所以致使運行期的內容與編譯期的內容有比較強的耦合。框架 另外有一些語言特性,屬於我的愛好上的緣由,也有一些差別,所以就決定本身編寫一個。函數 |
爲了更好的說明Tiny的語法規範,所以全程對比Velocity
${表達式}
表達式是指最後的運算結果是一個值,表達式中可使用變量
=>與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"
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( [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:
==用的是equals
能夠用下面的方式來避免與顯示內容分不開
#if(foo == bar)it's true!#{else}it's not!#end</li>
注意:與Velocity區別:變量名前面不要加「$」符號
Format:
# for(varName : collection) 顯示內容1 [#[{]else[}] ]  顯示內容2 # [ { ] end [ } ]
表示對集合進行循環,執行顯示內容1,若是集合爲空,則執行顯示內容2
注意:與Velocity區別:增了了#else指令
能夠是collection的內容:
數組、集合、Iterator,Enumeration,Map,對象,甚至null
若是不是集合對象,只是一個普通對象,就只循環次,這比較適合於有時候會返回列表,有時候會返回一個對象的狀況,就避免了增長複雜的判斷。
Format:
#include(expression[,{aa:1,bb:2}])
示例:
#include("/aa/bb/cc.vm")
#include("/aa/bb/cc.vm")
與Velocity的區別:用於把另外的頁面在當前位置進行渲染,後面只能加一個Map用來傳遞參數
Format:
#stop[(expresson)]
Usage:
#if(aa==bb)
#stop
#end
等價於
#stop(aa==bb)
Format:
#break[(expresson)]
Usage:
#if(aa==bb)
#break
#end
等價於
#break(aa==bb)
#continue[(expresson)]
Usage:
#if(aa==bb)
#continue
#end
等價於
#continue(aa==bb)
增長指令#[@]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
另外支持命名傳遞,詳見宏調用
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)
註釋:
##單行註釋
#-- ... --#  #* ... *#,兩種格式支持,是考慮到在<!-- -->的時候,改爲#-- --#更方便
非解析標記,下面的內容會原樣輸出
#[[
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的可是實在等不到,所以只好本身動手升級了。
凡有好的意見、建議、需求的,所有采納並快速實現,在此提早致以感謝!