原本是没有本身写一个模板引擎的计划的,由于按个人理解,一直认识这种“语言”级的引擎,难度是很是大的。总感受本身的水平不够,所以不敢有这个念头。直到大量使用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的可是实在等不到,所以只好本身动手升级了。
凡有好的意见、建议、需求的,所有采纳并快速实现,在此提早致以感谢!