Beetl2.7.16中文文檔
Beetl作者:李家智 <xiandafu@126.com>
1. 什么是Beetl
Beetl目前版本是2.7.16,相對于其他java模板引擎,具有功能齊全嗅榕,語法直觀,性能超高蝌以,以及編寫的模板容易維護等特點。使得開發(fā)和維護模板有很好的體驗。是新一代的模板引擎许师。總得來說,它的特性如下:
- 功能完備:作為主流模板引擎采够,Beetl具有相當多的功能和其他模板引擎不具備的功能肄方。適用于各種應用場景冰垄,從對響應速度有很高要求的大網(wǎng)站到功能繁多的CMS管理系統(tǒng)都適合。Beetl本身還具有很多獨特功能來完成模板編寫和維護权她,這是其他模板引擎所不具有的虹茶。
- 非常簡單:類似Javascript語法和習俗,只要半小時就能通過半學半猜完全掌握用法隅要。拒絕其他模板引擎那種非人性化的語法和習俗蝴罪。同時也能支持html 標簽,使得開發(fā)CMS系統(tǒng)比較容易
- 超高的性能:Beetl 遠超過主流java模板引擎性能(引擎性能5-6倍與freemaker步清,2倍于JSP要门。參考附錄),而且消耗較低的CPU廓啊。
- 易于整合:Beetl能很容易的與各種web框架整合欢搜,如Spring MVC,JFinal谴轮,Struts炒瘟,Nutz,Jodd第步,Servlet等疮装。
- 支持模板單獨開發(fā)和測試,即在MVC架構中粘都,即使沒有M和C部分廓推,也能開發(fā)和測試模板。
- 擴展和個性化:Beetl支持自定義方法翩隧,格式化函數(shù)樊展,虛擬屬性,標簽,和HTML標簽. 同時Beetl也支持自定義占位符和控制語句起始符號也支持使用者完全可以打造適合自己的工具包滚局。
關于性能
通過與主流模板引擎Freemarker居暖,Vecloity以及JSP對比,Beetl6倍于Freemarker藤肢,2倍于JSP太闺。這是因為宏觀上,通過了優(yōu)化的渲染引擎嘁圈,IO的二進制輸出省骂,字節(jié)碼屬性訪問增強,微觀上最住,通過一維數(shù)組保存上下文Context,靜態(tài)文本合并處理钞澳,通過重復使用字節(jié)數(shù)組來防止java頻繁的創(chuàng)建和銷毀數(shù)組,還使用模板緩存涨缚,運行時優(yōu)化等方法轧粟。詳情參考附錄
獨特功能
Beetl有些功能是發(fā)展了10多年的模板引擎所不具備的,這些功能非常利于模板的開發(fā)和維護脓魏,如下
- 自定義占位符和控制語句起始符號兰吟,這有利于減小模板語法對模板的傾入性,比如在html模板中茂翔,如果定義控制語句符號是``,那么混蔼,大部分模板文件都能通過瀏覽器打開。有的使用者僅僅采用了單個符號
@
(或者單個符號“~
”)以及回車換號作為控制語句起始符號珊燎,這又能提高開發(fā)效率- 可單獨測試的模板惭嚣。無需真正的控制層和模型層,Beetl的模板就可以單獨開發(fā)和測試
- 同時支持較為松散的MVC和嚴格的MVC悔政,如果在模板語言里嵌入計算表達式晚吞,復雜條件表達式,以及函數(shù)調(diào)用有干涉業(yè)務邏輯嫌疑卓箫,你可以禁止使用這些語法载矿。
- 強大的安全輸出,通過安全輸出符號烹卒!闷盔,能在模板變量,變量屬性引用旅急,for循環(huán)逢勾,占位符輸出,try-catch中等各個地方提供安全輸出藐吮,保證渲染正常溺拱。
- 模板變量:運行將模板的某一部分輸出像js那樣賦值給一個變量逃贝,稍后再處理。利用模板變量能完成非常復雜的頁面布局(簡單的布局可使用include,layout標簽函數(shù))
- 類型推測迫摔,能在運行的時候推測模板變量類型沐扳,從而優(yōu)化性能,也可以通過注解的方法顯示的說明模板變量屬性(這是非必須的句占,但有助于IDE自動提示功能)
- 可插拔的設計沪摄,錯誤信息提示,模板引擎緩存機制纱烘,模板資源管理杨拐,本地調(diào)用的安全管理器,嚴格MVC限制,模板引擎本身都有默認的實現(xiàn)擂啥,但又完全可以自定義以適合特定需求
- 增強的語法哄陶,如for-elsefor, select-case,安全輸出符號!,省略的三元表達式 等哺壶,這些語法特別適合模板開發(fā)
- 局部渲染技術屋吨,結合現(xiàn)在js的ajax技術。
- 性能超高,具有最快的模板解釋引擎变骡,同時离赫,又有較低的CPU消耗。5-6倍于國內(nèi)使用的Freemaker塌碌。適合各類模板應用,如代碼生成工具旬盯,CMS系統(tǒng)台妆,普通網(wǎng)站,超高訪問量的門戶系統(tǒng)胖翰,和富客戶端JS框架整合的后臺管理應用
小白如何開始
- 需要通讀基本用法接剩,大部分都是講解語法,而語法跟js很接近萨咳,所以可以快速預覽懊缺,但Beetl是針對模板設計, 所以像安全輸出培他,標簽和html標簽鹃两,全局變量,臨時變量和共享變量舀凛,布局技術俊扳,以及直接調(diào)用java代碼等還需要認真讀一遍。
- 如果從事web開發(fā)猛遍,還需要閱讀web集成里的第一節(jié)“web提供的全局變量”馋记,如果web里還使用ajax技術号坡,可以閱讀“整合ajax的局部渲染技術”。
- 包含有spring,jfinal,jodd,struts 等demo可以作為參考學習用https://git.oschina.net/xiandafu 任何問題梯醒,都可以在ibeetl.com 社區(qū)上提問宽堆。目前答復率是100%,提問需要詳細說明自己的期望茸习,出錯信息日麸,附上代碼或者圖片
聯(lián)系作者
作者:閑.大賦 (李家智)等(參考附錄查看代碼貢獻者)
QQ技術交流群:219324263
Beetl社區(qū):bbs.ibeetl.com
源碼主頁:https://github.com/javamonkey/beetl2.0
在線體驗和代碼分享 http://ibeetl.com/beetlonline/
2. 基本用法
2.1. 安裝
如果使用maven,請使用如下坐標
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>2.7.16</version>
</dependency>
如果非maven工程逮光,直接下載http://git.oschina.net/xiandafu/beetl2.0/attach_files
2.2. 從GroupTemplate開始
StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("hello,${name}");
t.binding("name", "beetl");
String str = t.render();
System.out.println(str);
Beetl的核心是GroupTemplate代箭,創(chuàng)建GroupTemplate需要倆個參數(shù),一個是模板資源加載器涕刚,一個是配置類嗡综,模板資源加載器Beetl內(nèi)置了6種,分別是
- StringTemplateResourceLoader:字符串模板加載器杜漠,用于加載字符串模板极景,如本例所示
- FileResourceLoader:文件模板加載器,需要一個根目錄作為參數(shù)構造驾茴,傳入getTemplate方法的String是模板文件相對于Root目錄的相對路徑
- ClasspathResourceLoader:文件模板加載器盼樟,模板文件位于Classpath里
- WebAppResourceLoader:用于webapp集成,假定模板根目錄就是WebRoot目錄锈至,參考web集成章
- MapResourceLoader : 可以動態(tài)存入模板
- CompositeResourceLoader 混合使用多種加載方式
代碼第5行將變量name傳入模板里晨缴,其值是“Beetl”。 代碼第6行是渲染模板峡捡,得到輸出击碗,template提供了多種獲得渲染輸出的方法,如下
- tempalte.render() 返回渲染結果们拙,如本例所示
- template.renderTo(Writer) 渲染結果輸出到Writer里
- template.renderTo(OutputStream ) 渲染結果輸出到OutputStream里
- 關于如何使用模板資源加載器稍途,請參考下一節(jié)
- 如何對模板進行配置,請參考下一節(jié)
2.3. 模板基礎配置
Beetl提供不但功能齊全砚婆,而且還有很多獨特功能械拍,通過簡單的配置文件,就可以定義眾多的功能装盯,默認情況下坷虑,Configuration類總是會先加載默認的配置文件(位于/org/beetl/core/beetl-default.properties,作為新手验夯,通常只需要關注3,4,5,6行定界符的配置猖吴,以及12行模板字符集的配置就可以了,其他配置會在后面章節(jié)陸續(xù)提到)下挥转,其內(nèi)容片斷如下:
#默認配置
ENGINE=org.beetl.core.engine.FastRuntimeEngine
DELIMITER_PLACEHOLDER_START=${
DELIMITER_PLACEHOLDER_END=}
DELIMITER_STATEMENT_START=<%
DELIMITER_STATEMENT_END=%>
DIRECT_BYTE_OUTPUT = FALSE
HTML_TAG_SUPPORT = true
HTML_TAG_FLAG = #
HTML_TAG_BINDING_ATTRIBUTE = var
NATIVE_CALL = TRUE
TEMPLATE_CHARSET = UTF-8
ERROR_HANDLER = org.beetl.core.ConsoleErrorHandler
NATIVE_SECUARTY_MANAGER= org.beetl.core.DefaultNativeSecurityManager
MVC_STRICT = FALSE
#資源配置海蔽,resource后的屬性只限于特定ResourceLoader
RESOURCE_LOADER=org.beetl.core.resource.ClasspathResourceLoader
#classpath 根路徑
RESOURCE.root= /
#是否檢測文件變化,開發(fā)用true合適共屈,但線上要改為false
RESOURCE.autoCheck= true
#自定義腳本方法文件的Root目錄和后綴
RESOURCE.functionRoot = functions
RESOURCE.functionSuffix = html
#自定義標簽文件Root目錄和后綴
RESOURCE.tagRoot = htmltag
RESOURCE.tagSuffix = tag
##### 擴展 ##############
## 內(nèi)置的方法
FN.date = org.beetl.ext.fn.DateFunction
......
##內(nèi)置的功能包
FNP.strutil = org.beetl.ext.fn.StringUtil
......
##內(nèi)置的默認格式化函數(shù)
FTC.java.util.Date = org.beetl.ext.format.DateFormat
.....
## 標簽類
TAG.include= org.beetl.ext.tag.IncludeTag
第2行配置引擎實現(xiàn)類,默認即可.
第3,4行指定了占位符號党窜,默認是${
}
拗引,也可以指定為其他占位符。
第5,6行指定了語句的定界符號幌衣,默認是<%
%>
矾削,也可以指定為其他定界符號
第7行指定IO輸出模式,默認是FALSE,即通常的字符輸出豁护,在考慮高性能情況下哼凯,可以設置成true
。詳細請參考高級用法
第8,9行指定了支持HTML標簽楚里,且符號為#,默認配置下断部,模板引擎識別<#tag ></#tag>
這樣的類似html標簽,并能調(diào)用相應的標簽函數(shù)或者模板文件班缎。你也可以指定別的符號蝴光,如bg: 則識別<bg:
第10行 指定如果標簽屬性有var
,則認為是需要綁定變量給模板的標簽函數(shù)
第11行指定允許本地Class直接調(diào)用
第12行指定模板字符集是UTF-8
第13行指定異常的解析類达址,默認是ConsoleErrorHandler蔑祟,他將在render發(fā)生異常的時候在后臺打印出錯誤信息(System.out
)。
第14行指定了本地Class調(diào)用的安全策略
第15行配置了是否進行嚴格MVC沉唠,通常情況下疆虚,此處設置為false.
第18行指定了默認使用的模板資源加載器,注意右冻,在beetl與其他MVC框架集成的時候装蓬,模板加載器不一定根據(jù)這個配置,比如spring纱扭,他的RESOURCE_LOADER以spring的配置為準
第20到22行配置了模板資源加載器的一些屬性,如設置根路徑為/,即Classpath的頂級路徑儡遮,并且總是檢測模板是否更改
第23行配置了自定義的方法所在的目錄以及文件名后綴乳蛾。beetl既支持通過java類定義方法,也支持通過模板文件來定義方法
第26行配置了自定義的html標簽所在的目錄以及文件名后綴鄙币。beetl既支持通過java類定義標簽肃叶,也支持通過模板文件來定義標簽
第31行注冊了一個date
方法,其實現(xiàn)類是org.beetl.ext.fn.DateFunction
第34行注冊了一個方法包strutil
十嘿,其實現(xiàn)類org.beetl.ext.fn.StringUtil
因惭,此類的每個public
方法都將注冊為beetl的方法
第37行注冊了一個日期格式化函數(shù)
第40行注冊了一個include
標簽函數(shù)
模板開發(fā)者可以創(chuàng)建一個beetl.properties的配置文件,此時绩衷,該配置文件將覆蓋默認的配置文件屬性蹦魔,比如激率,你的定界符考慮是`` ,則在beetl.properties加入一行即可,并將此配置文件放入Classpath根目錄下即可。 Configuration.defaultConfiguration()總是先加載系統(tǒng)默認的勿决,然后再加載Beetl.properties的配置屬性乒躺,如果有重復,用后者代替前者的配置
#自定義配置 DELIMITER_STATEMENT_START=<!--: DELIMITER_STATEMENT_END=-->
2.4.0 新功能:beetl 支持通過模板本生來完成函數(shù)低缩,即模板函數(shù)嘉冒,或者通過模板來實現(xiàn)HTML標簽(而不用寫java代碼),可以beetl.properties為這種應用設置的不同的語句定界符來跟常規(guī)模板做區(qū)分咆繁,如下
FUNCTION_TAG_LIMITER=<% ; %>
分號分割開讳推,如果配置文件沒有FUNCTION_TAG_LIMITER=,則模板函數(shù)玩般,html標簽使用同DELIMITER_STATEMENT_START银觅,DELIMITER_STATEMENT_END
2.4. 模板資源加載器
資源加載器是根據(jù)String值獲取Resource實例的工場類,同時資源加載器還要負責響應模板引擎詢問模板是否變化的調(diào)用壤短。對于新手來說设拟,無需考慮模板資源加載器如何實現(xiàn),只需要根據(jù)自己場景選擇系統(tǒng)提供的三類模板資源加載器即可
2.4.1. 字符串模板加載器
在創(chuàng)建GroupTemplate過程中久脯,如果傳入的是StringTemplateResourceLoader纳胧,則允許通過調(diào)用gt.getTemplate(String template)來獲取模板實例對象,如2.1所示
2.4.2. 文件資源模板加載器
更通常情況下帘撰,模板資源是以文件形式管理的跑慕,集中放在某一個文件目錄下(如webapp的模板根目錄就可能是WEB-INF/template里),因此摧找,可以使用FileResourceLoader來加載模板實例核行,如下代碼:
String root = System.getProperty("user.dir")+File.separator+"template";
FileResourceLoader resourceLoader = new FileResourceLoader(root,"utf-8");
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("/s01/hello.txt");
String str = t.render();
System.out.println(str);
第1行代碼指定了模板根目錄,即位于項目工程下的template目錄 第2行構造了一個資源加載器蹬耘,并指定字符集為UTF-8 (也可不指定芝雪,因為配置文件默認就是UTF-8); 第5行通過模板的相對路徑/s01/hello.txt來加載模板
2.4.3. Classpath資源模板加載器
還有種常情況下,模板資源是打包到jar文件或者同Class放在一起综苔,因此惩系,可以使用ClasspathResourceLoader來加載模板實例,如下代碼:
ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader("org/beetl/sample/s01/");
Configuration cfg = Configuration.defaultConfiguration();
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Template t = gt.getTemplate("/hello.txt");
String str = t.render();
System.out.println(str);
第1行代碼指定了模板根目錄如筛,即搜索模板的時候從根目錄開始堡牡,如果new ClasspathResourceLoader("template/"),則表示搜索template下的模板。此處用空構造函數(shù)杨刨,表示搜索路徑是根路徑晤柄,且字符集默認字符集UTF-8.
第4行通過模板的相對路徑org/beetl/sample/s01/hello.txt來加載模板
2.4.4. WebApp資源模板加載器
WebAppResourceLoader 是用于web應用的資源模板加載器,默認根路徑是WebRoot目錄妖胀。也可以通過制定root屬性來設置相對于WebRoot的的模板根路徑芥颈,從安全角考慮惠勒,建議放到WEB-INF目錄下
如下是Jfinal集成 里初始化GroupTemplate的方法
Configuration cfg = Configuration.defaultConfiguration();
WebAppResourceLoader resourceLoader = new WebAppResourceLoader();
groupTemplate = new GroupTemplate(resourceLoader, cfg);
WebAppResourceLoader 假定 beetl.jar 是位于 WEB-INF/lib 目錄下,因此浇借,可以通過WebAppResourceLoader類的路徑來推斷出WebRoot路徑從而指定模板根路徑捉撮。所有線上環(huán)境一般都是如此,如果是開發(fā)環(huán)境或者其他環(huán)境不符合此假設妇垢,你需要調(diào)用resourceLoader.setRoot() 來指定模板更路徑
2.4.5. 自定義資源模板加載器
有時候模板可能來自文件系統(tǒng)不同目錄巾遭,或者模板一部分來自某個文件系統(tǒng),另外一部分來自數(shù)據(jù)庫闯估,還有的情況模板可能是加密混淆的模板灼舍,此時需要自定義資源加載,繼承ResouceLoader才能實現(xiàn)模板功能涨薪,這部分請參考高級部分
2.5. 定界符與占位符號
Beetl模板語言類似JS語言和習俗骑素,只需要將Beetl語言放入定界符號里即可,如默認的是<% %> ,占位符用于靜態(tài)文本里嵌入占位符用于輸出刚夺,如下是正確例子
<%
var a = 2;
var b = 3;
var result = a+b;
%>
hello 2+3=${result}
千萬不要在定界符里使用占位符號献丑,因為占位符僅僅嵌在靜態(tài)文本里,如下例子是錯誤例子
<%
var a = "hi";
var c = ${a}+"beetl"; //應該是var c = a+"beetl"
%>
每次有人問我如上例子為啥不能運行的時候侠姑,我總是有點憎惡velocity 帶來的這種非人性語法
定界符和占位符 通常還有別的選擇创橄,如下定界符
- @ 和回車換行 (此時,模板配置DELIMITER_STATEMENT_END= 或者 DELIMITER_STATEMENT_END=null 都可以)
- #: 和回車換行
- <? 和 ?>
占位符--#{ }-##
你也可以與團隊達成一致意見來選擇團隊喜愛的定界符號和占位符號。
定界符號里是表達式莽红,如果表達式跟定界符或者占位符有沖突妥畏,可以在用 “\” 符號,如
@for(user in users){
email is ${user.name}\@163.com
@}
${[1,2,3]} //輸出一個json列表
${ {key:1,value:2 \} } //輸出一個json map,} 需要加上\
2.6. 注釋
Beetl語法類似js語法,所以注釋上也同js一樣: 單行注釋采用//
多行注視采用/**/
<%
/*此處是一個定義變量*/
var a = 3; //定義一個變量.
/* 以下內(nèi)容都將被注釋
%>
<% */ %>
第2行是一個多行注釋
第3行是一個單行注釋
第5行到第8行采用的是多行注釋件已,因此里面有內(nèi)容也是注釋,模板將不予處理
2.7. 臨時變量定義
在模板中定義的變量成為臨時變量痕惋,這類似js中采用var 定義的變量,如下例子
<%
var a = 3;
var b = 3,c = "abc",d=true,e=null;
var f = [1,2,3];
var g = {key1:a,key2:c};
var i = a+b;
%>
2.8. 全局變量定義
全局變量是通過template.binding傳入的變量,這些變量能在模板的任何一個地方,包括子模板都能訪問到。如java代碼里
template.binding("list",service.getUserList());
//在模板里
<%
for(user in list){
%>
hello,${user.name};
<% } %>
2.9. 共享變量
共享變量指在所有模板中都可以引用的變量确沸,可通過groupTemplate.setSharedVars(Map<String, Object> sharedVars)傳入變量,這些變量能用在 所有模板 的任何一個地方
//.....
GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
Map<String,Object> shared = new HashMap<String,Object>();
shared.put("name", "beetl");
gt.setSharedVars(shared);
Template t = gt.getTemplate("/org/beetl/sample/s0208/t1.txt");
String str = t.render();
System.out.println(str);
t = gt.getTemplate("/org/beetl/sample/s0208/t2.txt");
str = t.render();
System.out.println(str);
//t1.txt
hi,${name}
//t2.txt
hello,${name}
2.10. 模板變量
模板變量是一種特殊的變量,即可以將模板中任何一段的輸出賦值到該變量俘陷,并允許稍后在其他地方使用,如下代碼
<%
var content = {
var c = "1234";
print(c);
%>
模板其他內(nèi)容:
<% }; %>
第2行定義了一個模板變量content = { …} ; 此變量跟臨時變量一樣观谦,可以在其他地方使用拉盾,最常見的用法是用于復雜的布局。請參考高級用法布局
2.11. 引用屬性
屬性引用是模板中的重要一部分豁状,beetl支持屬性同javascript的支持方式一樣捉偏,如下
- Beetl支持通過”.”號來訪問對象的的屬性倒得,如果javascript一樣。如果User對象有個getName()方法夭禽,那么在模板中霞掺,可以通過${xxx.name}來訪問
- 如果模板變量是數(shù)組或者List類,這可以通過[] 來訪問讹躯,如${userList[0]}
- 如果模板變量是Map類菩彬,這可以通過[]來訪問,如${map[“name”]},如果key值是字符串類型潮梯,也可以使用${map.name}.但不建議這么使用骗灶,因為會讓模板閱讀者誤以為是一個Pojo對象
- Beetl也支持Generic Get方式,即如果對象有一個public Object get(String key)方法秉馏,可以通過”.”號或者[]來訪問耙旦,譬如 ${activityRecord.name}或者${activityRecord[“name”] }都將調(diào)用activityRecord的 get(String key)方法。如果對象既有具體屬性萝究,又有Generic get(這種模型設計方式是不值得鼓勵)免都,則以具體屬性優(yōu)先級高.
- Beetl也可以通過[]來引用屬性,如${user[“name”]} 相當于${user.name}.這跟javascript保持一致帆竹。但建議不這么做绕娘,因為容易讓閱讀模板的人誤認為這是一個Map類型
- Beetl 還可以定義額外的對象屬性,而無需更改java對象馆揉,這叫著虛擬屬性业舍,如,對于所有集合升酣,數(shù)組舷暮,都有共同的虛擬屬性size.虛擬屬性是“.~”+虛擬屬性名
template.binding("list",service.getUserList());
template.binding("pageMap",service.getPage());
//在模板里
總共 ${list.~size}
<%
for(user in list){
%>
hello,${user.name};
<% } %>
當前頁${pageMap['page']},總共${pageMap["total"]}
2.12. 屬性賦值
Beetl2.7.0 開始支持對象賦值,如:
<%
var user = ....
user.name="joelli";
user.friends[0] = getNewUser();
user.map["name"] = "joelli";
%>
2.13. 算數(shù)表達式
Beetl支持類似javascript的算術表達式和條件表達式噩茄,如+ - * / % 以及()下面,以及自增++,自減--
<%
var a = 1;
var b = "hi";
var c = a++;
var d = a+100.232;
var e = (d+12)*a;
var f = 122228833330322.1112h
%>
Beetl里定義的臨時變量類型默認對應的java類型是Int型或者double類型绩聘,對于模板常用情況沥割,已經(jīng)夠了.如果需要定義長精度類型(對應java的BigDecimal),則需要在數(shù)字末尾加上h以表示這是長精度BigDecimal凿菩,其后的計算和輸出以及邏輯表達式都將按照長精度類型來考慮机杜。
2.14. 邏輯表達式
Beetl支持類似Javascript,java的條件表達式 如>,<衅谷,==椒拗,!=,>= , <= 以及 !, 還有&&和 || ,還有三元表達式等蚀苛,如下例子
<%
var a = 1;
var b="good";
var c = null;
if(a!=1&&b=="good"&&c==null){
......
}
%>
三元表達式如果只考慮true條件對應的值的話在验,可以做簡化,如下倆行效果是一樣的。
<%
var a = 1 ;
%>
${a==1?"ok":''}
${a==1?"ok"}
2.15. 循環(huán)語句
Beetl支持豐富的循環(huán)方式堵未,如for-in,for(exp;exp;exp)腋舌,以及while循環(huán),以及循環(huán)控制語句break;continue; 另外渗蟹,如果沒有進入for循環(huán)體块饺,還可以執(zhí)行elsefor指定的語句。
2.15.1. for-in
for-in循環(huán)支持遍歷集合對象拙徽,對于List和數(shù)組來說以及Iterator刨沦,對象就是集合對象,對于Map來說膘怕,對象就是Map.entry,如下倆個例子
<%
for(user in userList){
print(userLP.index);
print(user.name);
}
%>
第三行代碼userLP是Beetl隱含定義的變量想诅,能在循環(huán)體內(nèi)使用。其命名規(guī)范是item名稱后加上LP岛心,他提供了當前循環(huán)的信息来破,如
- **userLP.index **當前的索引,從1開始
- **userLP.size **集合的長度
- userLP.first 是否是第一個
- userLP.last 是否是最后一個
- userLP.even 索引是否是偶數(shù)
- userLP.odd 索引是否是奇數(shù)
如何記住后綴是LP忘古,有倆個訣竅徘禁,英語棒的是Loop的縮寫,拼音好的是老婆的拼音縮寫髓堪,這可以讓程序員每次寫到這的時候都會想想老婆(不管有沒有送朱,哈哈)
如下是Map使用例子
<%
for(entry in map){
var key = entry.key;
var value = entry.value;
print(value.name);
}
%>
2.15.2. for(exp;exp;exp)
對于渲染邏輯更為常見的是經(jīng)典的for循環(huán)語句,如下例子
<%
var a = [1,2,3];
for(var i=0;i<a.~size;i++){
print(a[i]);
}
%>
2.15.3. while
對于渲染邏輯同樣常見的有的while循環(huán)語句干旁,如下例子
<%
var i = 0;
while(i<5){
print(i);
i++;
}
%>
2.15.4. elsefor
不同于通常程序語言驶沼,如果沒有進入循環(huán)體,則不需額外的處理争群,模板渲染邏輯更常見情況是如果沒有進入循環(huán)體回怜,還需要做點什么,因此换薄,對于for循環(huán)來說玉雾,還有elsefor 用來表達如果循環(huán)體沒有進入,則執(zhí)行elsefor 后的語句
<%
var list = [];
for(item in list){
}elsefor{
print("未有記錄");
}
%>
2.16. 條件語句
2.16.1. if else
同js一樣轻要,支持if else,如下例子
<%
var a =true;
var b = 1;
if(a&&b==1){
}else if(a){
}else{
}
%>
2.16.2. switch-case
同js一樣复旬,支持switch-case,如下例子
<%
var b = 1;
switch(b){
case 0:
print("it's 0");
break;
case 1:
print("it's 1");
break;
default:
print("error");
}
%>
switch變量可以支持任何類型,而不像js那樣只能是整形
2.16.3. select-case
select-case 是switch case的增強版冲泥。他允許case 里有邏輯表達式赢底,同時,也不需要每個case都break一下,默認遇到合乎條件的case執(zhí)行后就退出幸冻。
<%
var b = 1;
select(b){
case 0,1:
print("it's small int");
case 2,3:
print("it's big int");
default:
print("error");
}
%>
select 后也不需要一個變量,這樣case 后的邏輯表達式將決定執(zhí)行哪個case.其格式是
<%
select {
case boolExp,orBoolExp2:
doSomething();
}
%>
<%
var b = 1;
select{
case b<1,b>10:
print("it's out of range");
break;
case b==1:
print("it's 1");
break;
default:
print("error");
}
%>
2.17. try-catch
通常模板渲染邏輯很少用到try-catch 但考慮到渲染邏輯復雜性咳焚,以及模板也有不可控的地方洽损,所以提供try catch,在渲染失敗的時候仍然能保證輸出正常
<%
try{
callOtherSystemView()
}catch(error){
print("暫時無數(shù)據(jù)");
}
%>
error代表了一個異常革半,你可以通過error.message 來獲取可能的錯誤信息
也可以省略catch部分碑定,這樣出現(xiàn)異常,不做任何操作
2.18. 虛擬屬性
虛擬屬性也是對象的屬性又官,是虛擬的延刘,非模型對象的真實屬性,這樣的好處是當模板需要額外的用于顯示的屬性的時候但又不想更改模型六敬,便可以采用這種辦法 如beetl內(nèi)置的虛擬屬性.~size 針對了數(shù)組以及集合類型碘赖。
${user.gender}
${user.~genderShowName}
~genderShowName 是虛擬屬性,其內(nèi)部實現(xiàn)根據(jù)boolean變量gender來顯示性別
如何完成虛擬屬性外构,請參考高級用法
2.19. 函數(shù)調(diào)用
Beetl內(nèi)置了少量實用函數(shù)普泡,可以在Beetl任何地方調(diào)用。如下例子是調(diào)用date 函數(shù)审编,不傳參數(shù)情況下撼班,返回當前日期
<%
var date = date();
var len = strutil.length("cbd");
println("len="+len);
%>
注意函數(shù)名支持namespace方式,因此代碼第3行調(diào)用的函數(shù)是strutil.length
定義beetl的方法非常容易垒酬,有三種方法
- 實現(xiàn)Function類的call方法砰嘁,并添加到配置文件里,或者顯示的通過代碼注冊registerFunction(name,yourFunction)
- 可以直接調(diào)用registerFunctionPackage(namespace,yourJavaObject),這時候yourJavaObject里的所有public方法都將注冊為Beetl方法勘究,方法名是namespace+"."+方法名
- 可以直接寫模板文件并且以html作為后綴矮湘,放到root/functions目錄下,這樣此模板文件自動注冊為一個函數(shù)乱顾,其函數(shù)名是該模板文件名板祝。
詳情請參考高級用法
Beetl內(nèi)置函數(shù)請參考附錄,以下列出了常用的函數(shù)
- date 返回一個java.util.Date類型的變量走净,如 date() 返回一個當前時間(對應java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期
- print 打印一個對象 print(user.name);
- println 打印一個對象以及回車換行符號券时,回車換號符號使用的是模板本身的,而不是本地系統(tǒng)的.如果僅僅打印一個換行符伏伯,則直接調(diào)用println() 即可
- nvl 函數(shù)nvl橘洞,如果對象為null,則返回第二個參數(shù)说搅,否則炸枣,返回自己 nvl(user,"不存在")
- isEmpty 判斷變量或者表達式是否為空,變量不存在,變量為null适肠,變量是空字符串霍衫,變量是空集合,變量是空數(shù)組侯养,此函數(shù)都將返回true
- isNotEmpty 同上敦跌,判斷對象是否不為空
- has 變量名為參數(shù),判斷是否存在此全局變量逛揩,如 has(userList),類似于1.x版本的exist("userList"),但不需要輸入引號了
- assert 如果表達式為false柠傍,則拋出異常
- trunc 截取數(shù)字,保留指定的小數(shù)位辩稽,如trunc(12.456,2) 輸出是12.45
- decode 一個簡化的if else 結構惧笛,如 decode(a,1,"a=1",2,"a=2","不知道了")},如果a是1,這decode輸出"a=1",如果a是2逞泄,則輸出"a==2", 如果是其他值患整,則輸出"不知道了"
- debug 在控制臺輸出debug指定的對象以及所在模板文件以及模板中的行數(shù),如debug(1),則輸出1 [在3行@/org/beetl/core/lab/hello.txt],也可以輸出多個炭懊,如debug("hi",a),則輸出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]
- parseInt 將數(shù)字或者字符解析為整形 如 parseInt("123");
- parseLong 將數(shù)字或者字符解析為長整形并级,parseInt(123.12);
- parseDouble 將數(shù)字或者字符解析為浮點類型 如parseDouble("1.23")
- range 接收三個參數(shù),初始值侮腹,結束值嘲碧,還有步增(可以不需要,則默認為1)父阻,返回一個Iterator愈涩,常用于循環(huán)中,如for(var i in range(1,5)) {print(i)},將依次打印1234.
- flush 強制io輸出加矛。
- json履婉,將對象轉成json字符串,如 var data = json(userList) 可以跟一個序列化規(guī)則 如,var data = json(userList,"[*].id:i"),具體參考 https://git.oschina.net/xiandafu/beetl-json
- pageCtx 斟览,僅僅在web開發(fā)中毁腿,設置一個變量,然后可以在頁面渲染過程中苛茂,調(diào)用此api獲取已烤,如pageCtx("title","用戶添加頁面"),在其后任何地方妓羊,可以pageCtx("title") 獲取該變量
- type.new 創(chuàng)建一個對象實例胯究,如 var user = type.new("com.xx.User"); 如果配置了IMPORT_PACKAGE,則可以省略包名躁绸,type.new("User")
- type.name 返回一個實例的名字裕循,var userClassName = type.name(user),返回"User"
- global 返回一個全局變量值臣嚣,參數(shù)是一個字符串,如 var user = global("user_"+i);
- cookie 返回指定的cookie對象 剥哑,如var userCook = cookie("user"),allCookies = cookie();
2.20. 安全輸出
安全輸出是任何一個模板引擎必須重視的問題硅则,否則,將極大困擾模板開發(fā)者星持。Beetl中抢埋,如果要輸出的模板變量為null,則beetl將不做輸出督暂,這點不同于JSP,JSP輸出null穷吮,也不同于Freemarker逻翁,如果沒有用!,它會報錯.
模板中還有倆種情況會導致模板輸出異常
- 有時候模板變量并不存在(譬如子模板里)
- 模板變量為null,但輸出的是此變量的一個屬性捡鱼,如${user.wife.name}
針對前倆種種情況八回,可以在變量引用后加上!以提醒beetl這是一個安全輸出的變量驾诈。
如${user.wife.name! },即使user不存在缠诅,或者user為null,或者user.wife為null乍迄,或者user.wife.name為null beetl都不將輸出
可以在!后增加一個常量(字符串管引,數(shù)字類型等),或者另外一個變量闯两,方法褥伴,本地調(diào)用,作為默認輸出漾狼,譬如:
${user.wife.name!”單身”}重慢,如果user為null,或者user.wife為null逊躁,或者user.wife.name為null似踱,輸出”單身”
譬如
${user.birthday!@System.constants.DefaultBir}, 表示如果user為null稽煤,或者user. birthday為null核芽,輸出System.constants.DefaultBir
還有一種情況很少發(fā)生,但也有可能念脯,輸出模板變量發(fā)生的任何異常狞洋,如變量內(nèi)部拋出的一個異常
這需要使用格式${!(變量)},這樣,在變量引用發(fā)生任何異常情況下绿店,都不作輸出吉懊,譬如
${!(user.name)},庐橙,beetl將會調(diào)用user.getName()方法,如果發(fā)生異常借嗽,beetl將會忽略此異常态鳖,繼續(xù)渲染
值得注意的是,在變量后加上!不僅僅可以應用于占位符輸出(但主要是應用于占位符輸出)恶导,也可以用于表達式中浆竭,如:
<%
var k = user.name!'N/A'+user.age!;
%>
<%
${k}
%>
如果user為null,則k值將為N/A
在有些模板里惨寿,可能整個模板都需要安全輸出邦泄,也可能模板的部分需要安全輸出,使用者不必為每一個表達式使用裂垦!顺囊,可以使用beetl的安全指示符號來完成安全輸出 如:
<%
DIRECTIVE SAFE_OUTPUT_OPEN;
%>
${user.wife.name}
模板其他內(nèi)容,均能安全輸出……
<%
//關閉安全輸出蕉拢。
DIRECTIVE SAFE_OUTPUT_CLOSE;
%>
Beetl不建議每一個頁面都使用DIRECTIVE SAFE_OUTPUT_OPEN特碳,這樣,如果如果真有不期望的錯誤晕换,不容易及時發(fā)現(xiàn)午乓,其次,安全輸出意味著beetl會有額外的代碼檢測值是否存在或者是否為null闸准,性能會略差點益愈。所以建議及時關閉安全輸出(這不是必須的,但頁面所有地方是安全輸出恕汇,可能不容易發(fā)現(xiàn)錯誤)
在for-in 循環(huán)中 腕唧,也可以為集合變量增加安全輸出指示符號,這樣瘾英,如果集合變量為null枣接,也可以不進入循環(huán)體,如:
<%
var list = null;
for(item in list!){
}elsefor{
print("no data");
}
%>
2.20.1. 變量是否存在
<%
if(has(flag)){
print("flag變量存在缺谴,可以訪問")
}
%>
如果需要判斷變量是否存在但惶,如果存在,還有其他判斷條件湿蛔,通常都這么寫
<%
if(has(flag)&&flag==0){
//code
}
%>
如果flag存在膀曾,而且值是0,都將執(zhí)行if語句
但是阳啥,有更為簡便的方法是直接用安全輸出添谊,如
<%
if(flag!0==0){
//code
}
%>
flag!0 取值是這樣的,如果flag不存在察迟,則為0斩狱,如果存在耳高,則取值flag的值,類似三元表達式 if((has(flag)?flag:0)==0)
2.20.2. 安全輸出表達式
安全輸出表達式可以包括
- 字符串常量,如 ${user.count!"無結果"}
- boolean常量 ${user.count!false}
- 數(shù)字常量所踊,僅限于正數(shù)泌枪,因為如果是負數(shù),則類似減號秕岛,容易誤用碌燕,因此,如果需要表示負數(shù)继薛,請用括號修壕,如${user.count!(-1)}
- class直接調(diào)用,如${user.count!@User.DEFAULT_NUM}
- 方法調(diào)用遏考,如 ${user.count!getDefault() }
- 屬性引用叠殷,如 ${user.count!user.maxCount }
- 任何表達式,需要用括號
2.21. 格式化
幾乎所有的模板語言都支持格式化诈皿,Beetl也不列外,如下例子Beetl提供的內(nèi)置日期格式
<% var date = date(); %>
Today is ${date,dateFormat="yyyy-MM-dd"}.
Today is ${date,dateFormat}
salary is ${salary,numberFormat="##.##"}
格式化函數(shù)只需要一個字符串作為參數(shù)放在=號后面像棘,如果沒有為格式化函數(shù)輸入?yún)?shù)稽亏,則使用默認值,dateFormat格式化函數(shù)默認值是local
Beetl也允許為指定的java class設定格式化函數(shù)缕题,譬如已經(jīng)內(nèi)置了對java.util.Date,java.sql.Date 設置了了格式化函數(shù)截歉,因此上面的例子可以簡化為
${date,“yyyy-MM-dd”}
Beetl針對日期和數(shù)字類型提供的默認的格式化函數(shù),在org/beetl/core/beetl-default.properties里烟零,注冊了
##內(nèi)置的格式化函數(shù)
FT.dateFormat = org.beetl.ext.format.DateFormat
FT.numberFormat = org.beetl.ext.format.NumberFormat
##內(nèi)置的默認格式化函數(shù)
FTC.java.util.Date = org.beetl.ext.format.DateFormat
FTC.java.sql.Date = org.beetl.ext.format.DateFormat
FTC.java.sql.Time = org.beetl.ext.format.DateFormat
FTC.java.sql.Timestamp = org.beetl.ext.format.DateFormat
FTC.java.lang.Short = org.beetl.ext.format.NumberFormat
FTC.java.lang.Long = org.beetl.ext.format.NumberFormat
FTC.java.lang.Integer = org.beetl.ext.format.NumberFormat
FTC.java.lang.Float = org.beetl.ext.format.NumberFormat
FTC.java.lang.Double = org.beetl.ext.format.NumberFormat
FTC.java.math.BigInteger = org.beetl.ext.format.NumberFormat
FTC.java.math.BigDecimal = org.beetl.ext.format.NumberFormat
FTC.java.util.concurrent.atomic.AtomicLong = org.beetl.ext.format.NumberFormat
FTC.java.util.concurrent.atomic.AtomicInteger = org.beetl.ext.format.NumberFormat
2.22. 標簽函數(shù)
所謂標簽函數(shù)瘪松,即允許處理模板文件里的一塊內(nèi)容,功能等于同jsp tag锨阿。如Beetl內(nèi)置的layout標簽
index.html
<%
layout("/inc/layout.html",{title:'主題'}){
%>
Hello,this is main part
<% } %>
layout.html
title is ${title}
body content ${layoutContent}
footer
第1行變量title來自于layout標簽函數(shù)的參數(shù)
第2行l(wèi)ayoutContent 是layout標簽體{}渲染后的結果
關于layout標簽宵睦,參考高級主題布局
Beetl內(nèi)置了另外一個標簽是include,允許 include 另外一個模板文件
<%
include("/inc/header.html"){}
%>
在標簽中,{} 內(nèi)容將依據(jù)標簽的實現(xiàn)而執(zhí)行墅诡,layout標簽將執(zhí)行{}中的內(nèi)容壳嚎,而include標簽則忽略標簽體內(nèi)容。
關于如何實現(xiàn)標簽函數(shù)末早,請參考高級主題,如下是一個簡單的的標簽函數(shù):
public class CompressTag extends Tag{
@Override
public void render(){
BodyContent content = getBodyContent();
String content = content.getBody();
String zip = compress(conent);
ctx.byteWriter.write(zip);
}
}
2.23. HTML標簽
Beetl 也支持HTML tag形式的標簽烟馅, 區(qū)分beetl的html tag 與 標準html tag。如設定HTML_TAG_FLAG=#然磷,則如下html tag將被beetl解析
<#footer style=”simple”/>
<#richeditor id=”rid” path="${ctxPath}/upload" name=”rname” maxlength=”${maxlength}”> ${html} …其他模板內(nèi)容 </#richdeitor>
<#html:input id=’aaaa’ />
如對于標簽footer,Beetl默認會尋找WebRoot/htmltag/footer.tag(可以通過配置文件修改路徑和后綴) ,內(nèi)容如下:
<% if(style==’simple’){ %>
請聯(lián)系我 ${session.user.name}
<% }else{ %>
請聯(lián)系我 ${session.user.name},phone:${session.user.phone}
<% } %>
如下還包含了自定義html標簽一些一些規(guī)則
- 可以在自定義標簽里引用標簽體的內(nèi)容郑趁,標簽體可以是普通文本,beetl模板姿搜,以及嵌套的自定義標簽等寡润。如上<#richeditor 標簽體里捆憎,可用“tagBody”來引用
- HTML自定義標簽 的屬性值均為字符串 如<#input value=”123” />,在input.tag文件里 變量value的類型是字符串
- 可以在屬性標簽里引用beetl變量,如<#input value=”${user.age}” />悦穿,此時在input.tag里攻礼,value的類型取決于user.age
- 在屬性里引用beetl變量,不支持格式化栗柒,如<#input value=”${user.date,‘yyyy-MM-dd’ }” />,如果需要格式化礁扮,需要在input.tag文件里自行格式化
- 在標簽屬性里傳json變量需要謹慎,因為json包含了"}",容易與占位符混合導致解析出錯瞬沦,因此得使用""符號太伊,如<#input value=”${ {age:25} }” />
- html tag 屬性名將作為 其對應模板的變量名。
- 默認機制下逛钻,全局變量都將傳給html tag對應的模板文件僚焦,這個跟include一樣。當然曙痘,這機制也可以改變芳悲,對于標簽來說,通常是作為一個組件存在边坤,也不一定需要完全傳送所有全局變量名扛,而只傳送(request,session,這樣變量),因此需要重新繼承org.beetl.ext.tag.HTMLTagSupportWrapper.并重載callHtmlTag方法茧痒。并注冊為htmltag標簽肮韧。具體請參考https://github.com/javamonkey/beetl2.0/blob/master/beetl-core/src/test/java/org/beetl/core/tag/HtmlTagTest.java
如果采用模板來寫html標簽功能不夠強大,beetl支持寫標簽函數(shù)(參考上一節(jié))來實現(xiàn)html標簽旺订,標簽函數(shù)args[0]表示標簽名弄企,這通常沒有什么用處,args[1] 則是標簽的屬性区拳,參數(shù)是個map拘领,key是html tag的屬性,value是其屬性值劳闹,如下用java完成的html 標簽用于輸出屬性值
public class SimpleHtmlTag extends Tag{
@Override
public void render(){
String tagName = (String) this.args[0];
Map attrs = (Map) args[1];
String value = (String) attrs.get("attr");
try{
this.ctx.byteWriter.writeString(value);
}catch (IOException e){
}
}
}
如果注冊gt.registerTag("simpleTag", SimpleHtmlTag.class); 則如下模板輸出了attr屬性值abc
<#simpleTag attr="abc"></#simpleTag>
HTML_TAG_FLAG默認為#用來區(qū)別是否是beetl的html tag院究,你也可以設置成其他符號,比如 "my:",這樣本涕,<my:table></my:table> 其實是一個指向table.tag的標簽實現(xiàn)
2.24. 綁定變量的HTML標簽
對于html標簽(參考上一節(jié))业汰,Beetl還 支持將標簽實現(xiàn)類(java代碼)里的對象作為臨時變量,被標簽體引用菩颖。此時需要實現(xiàn)GeneralVarTagBinding (此類是Tag的子類) 該類提供另外3個個方法 - void binds(Object… array) 子類在render方法里調(diào)用此類以實現(xiàn)變量綁定样漆,綁定順序同在模板中聲明的順序 - void bind(String name, Object value) 子類在render方法里調(diào)用此類以實現(xiàn)變量綁定,name是模板中聲明的變量名晦闰,用此方法綁定不如binds更靈活放祟,不再推薦 - Object getAttributeValue 獲得標簽的屬性 - Map getAttributes 獲得標簽的所有屬性
public class TagSample extends GeneralVarTagBinding{
@Override
public void render(){
int limit = Integer.parseInt((String) this.getAttributeValue("limit"));
for (int i = 0; i < limit; i++){
this.binds(i)
this.doBodyRender();
}
}
}
//在某處注冊一下標簽TagSample
//gt.registerTag("tag", TagSample.class);
如上例子鳍怨,render方法將循環(huán)渲染標簽體limit次,且每次都將value賦值為i跪妥。我們再看看模板如何寫的
<#tag limit="3";value>
${value}
</#tag>
類似于常規(guī)html標簽鞋喇,需要在標簽的最后的屬性定義后面加上分號 ";" 此分號表示這個是一個需要在標簽運行時需要綁定變量的標簽。后跟上要綁定的變量列表眉撵,如上例只綁定了一個value變量侦香,如果需要綁定多個變量,則用逗號分開纽疟,如var1,var2 上罐韩。如果后面沒有變量列表,只有分號污朽,則默認綁定到標簽名同名的變量上. 如果標簽有namesapce散吵,則默認綁定訂的變量名不包含namespace
注意,由于標簽使用因為太長可能換行或者是文本格式化導致?lián)Q行蟆肆,目前beetl只允許在屬性之間換行矾睦,否則,將報標簽解析錯誤炎功。
默認情況下顷锰,如果標簽屬性出現(xiàn)了var(可以通過配置文件改成其他屬性名),也認為是綁定變量的標簽亡问,如上面的例子也可以這么寫
<#tag limit="3" var="value">
${value}
</#tag>
var屬性的值可以是個以逗號分開的變量名列表,如var="total,customer,index"
2.25. 直接調(diào)用java方法和屬性
可以通過符號@來表明后面表達式調(diào)用是java風格肛宋,可以調(diào)用對象的方法,屬性
${@user.getMaxFriend(“l(fā)ucy”)}
${@user.maxFriend[0].getName()}
${@com.xxxx.constants.Order.getMaxNum()}
${@com.xxxx.User$Gender.MAN}
<%
var max = @com.xxxx.constants.Order.MAX_NUM;
var c =1;
var d = @user.getAge(c);
%>
可以調(diào)用instance的public方法和屬性,也可以調(diào)用靜態(tài)類的屬性和方法 ,需要加一個 @指示此調(diào)用是直接調(diào)用class输钩,其后的表達式是java風格的翼虫。
- GroupTemplate可以配置為不允許直接調(diào)用Class,具體請參考配置文件.
- 也可以通過安全管理器配置到底哪些類Beetl不允許調(diào)用沉帮,具體請參考高級用法锈死。默認情況,java.lang.Runtime,和 java.lang.Process不允許在模板里調(diào)用穆壕。你自己的安全管理器也可以配置為不能直接訪問DAO類(避免了以前jsp可以訪問任意代碼帶來的危害)
- 請按照java規(guī)范寫類名和方法名待牵,屬性名。這樣便于beetl識別到底調(diào)用的是哪個類喇勋,哪個方法缨该。否則會拋出錯誤
- 可以省略包名,只用類名川背。beetl將搜索包路徑找到合適的類(需要設置配置“IMPORT_PACKAGE=包名.;包名.”贰拿,包名后需要跟一個“.”, 或者調(diào)用Configuration.addPkg)方法具體請參考附件配置文件說明
- 內(nèi)部類(包括枚舉)訪問同java一樣蛤袒,如User類有個內(nèi)部枚舉類Gender,訪問是User$Gender
- 表達式是java風格膨更,但參數(shù)仍然是beetl表達式妙真,比如 @user.sayHello(user.name).這里user.sayHello是java調(diào)用,user.name 仍然是beetl表達式
2.26. 嚴格MVC控制
如果在配置文件中設置了嚴格MVC荚守,則以下語法將不在模板文件里允許珍德,否則將報出STRICK_MVC 錯誤
- 定義變量,為變量賦值,如var a = 12是非法的
- 算術表達式 如${user.age+12}是非法的
- 除了只允許布爾以外健蕊,不允許邏輯表達式和方法調(diào)用 如if(user.gender==1)是非法的
- 方法調(diào)用菱阵,如${subString(string,1)}是非法的
- Class方法和屬性調(diào)用,如${@user.getName()}是非法的
- 嚴格的MVC缩功,非常有助于邏輯與視圖的分離晴及,特別當邏輯與視圖是由倆個團隊來完成的。如果你嗜好嚴格MVC嫡锌,可以調(diào)用groupTemplate.enableStrict()
通過重載AntlrProgramBuilder虑稼,可以按照自己的方法控制到底哪些語法是不允許在模板引擎中出現(xiàn)的,但這已經(jīng)超出了Beetl模板的基礎使用
2.27. 指令
指令格式為: DIRECTIVE 指令名 指令參數(shù)(可選) Beetl目前支持安全輸出指令势木,分別是
- DIRECTIVE SAFE_OUTPUT_OPEN ; 打開安全輸出功能蛛倦,此指令后的所有表達式都具有安全輸出功能,
- DIRECTIVE SAFE_OUTPUT_CLOSE ; 關閉安全輸出功能啦桌。詳情參考安全輸出
- DIRECTIVE DYNAMIC varName1,varName2 …指示后面的變量是動態(tài)類型溯壶,Beetl應該考慮為Object. 也可以省略后面的變量名,則表示模板里所有變量都是Object
<% DIRECTIVE DYNAMIC idList;
for(value in idList) .....
DYNAMIC 通常用在組件模板里甫男,因為組件模板可以接收任何類型的對象且改。如列表控件,可以接收任何含有id和 value屬性的對象板驳。
- 注意 DYNAMIC 后的變量名也允許用引號又跛,這主要是兼容Beetl1.x版本
- Beetl1.x 指令都是大寫,當前版本也允許小寫若治,如 directive dynamic idList
2.28. 類型聲明
Beetl 本質上還是強類型的模板引擎慨蓝,即模板每個變量類型是特定的,在模板運行過程中端幼,beetl 會根據(jù)全局變量自動推測出模板中各種變量和表達式類型礼烈。 也可以通過類型申明來說明beetl全局變量的類型,如下格式
<%
/**
*@type (List<User> idList,User user)
*/
for(value in idList) .....
類型申明必須放到多行注釋里婆跑,格式是@type( … ),里面的申明類似java方法的參數(shù)申明济丘。正如你看到的類型申明是在注釋里,也就表明了這在Beetl模板引擎中不是必須的,或者你只需要申明一部分即可摹迷,之所以提供可選的類型說明疟赊,是因為
- 提高一點性能
- 最重要的是,提高了模板的可維護性峡碉〗矗可以讓模板維護者知道變量類型,也可以讓未來的ide插件根據(jù)類型聲明來提供屬性提示鲫寄,重構等高級功能
需要注意的是吉执,如果在類型聲明里提供的是類名,而不是類全路徑地来,這樣必須在配置文件里申明類的搜索路徑((需要設置配置IMPORT_PACKAGE=包名.;包名.戳玫,或者調(diào)用Configuration.addPkg)),默認的搜索路徑有java.util. 和 java.lang.
類型聲明本用于eclipse插件用來提示未斑,但eclipse插件暫時沒有時間去做咕宿,所以類型申明現(xiàn)在不推薦使用
2.29. 錯誤處理
Beetl能較為詳細的顯示錯誤原因,包括錯誤行數(shù)蜡秽,錯誤符號府阀,錯誤內(nèi)容附近的模板內(nèi)容,以及錯誤原因芽突,如果有異常试浙,還包括異常和異常信息。 默認情況下寞蚌,僅僅在控制臺顯示田巴,如下代碼:
<%
var a = 1;
var b = a/0;
%>
運行此模板后,錯誤提示如下
>>DIV_ZERO_ERROR:0 位于3行 資源:/org/beetl/sample/s0125/error1.txt
1|<%
2|var a = 1;
3|var b = a/0;
4| %>
<%
var a = 1;
var b = a
var c = a+2;
%>
運行此模板后
>>缺少符號(PARSER_MISS_ERROR):缺少輸入 ';' 在 'var' 位于4行 資源:/org/beetl/sample/s0125/error2.txt
1|<%
2|var a = 1;
3|var b = a
4|var c = a+2;
5| %>
- 默認的錯誤處理器僅僅像后臺打印錯誤挟秤,并沒有拋出異常固额,如果需要在render錯誤時候拋出異常到控制層,則可以使用org.beetl.core.ReThrowConsoleErrorHandler煞聪。不僅打印異常,還拋出BeetlException
- 可以自定義異常處理器逝慧,比如把錯誤輸出到 作為渲染結果一部分輸出昔脯,或者輸出更美觀的html內(nèi)容等,具體參考高級用法
- 可以在配置文件不設置異常笛臣,這樣Beetl引擎將不處理異常云稚,用戶可以在外部來處理(可以在外部調(diào)用ErrorHandler子類來顯示異常)
2.30. Beetl小工具
BeetlKit 提供了一些便利的方法讓你立刻能使用Beetl模板引擎。提供了如下方法
-
public static String render(String template, Map<String, Object> paras)
渲染模板沈堡,使用paras參數(shù)静陈,渲染結果作為字符串返回 -
public static void renderTo(String template, Writer writer, Map<String, Object> paras)
渲染模板,使用paras參數(shù) -
public static void execute(String script, Map<String, Object> paras)
執(zhí)行某個腳本 -
public static Map execute(String script, Map<String, Object> paras, String[] locals)
執(zhí)行某個腳本,將locals指定的變量名和模板執(zhí)行后相應值放入到返回的Map里 -
public static Map executeAndReturnRootScopeVars(String script)
執(zhí)行某個腳本鲸拥,返回所有頂級scope的所有變量和值 -
public static String testTemplate(String template, String initValue)
渲染模板template拐格,其變量來源于intValue腳本運行的結果,其所有頂級Scope的變量都將作為template的變量
String template = "var a=1,c=2+1;";
Map result = executeAndReturnRootScopeVars(template);
System.out.println(result);
//輸出結果是{c=3, a=1}
BeetlKit 不要用于線上系統(tǒng)刑赶。僅僅作為體驗Beetl功能而提供的捏浊,如果需要在線上使用這些功能,請參考該類源碼自行擴展
2.31. 瑣碎功能
- 對齊:我發(fā)現(xiàn)別的模板語言要是做到對齊撞叨,非常困難,使用Beetl你完全不用擔心金踪,比如velocty,stringtemlate牵敷,freemarker例子都出現(xiàn)了不對齊的情況胡岔,影響了美觀,Beetl完全無需擔心輸出對齊
- Escape:可以使用\ 做escape 符號枷餐,如$monkey$ 將作為一個普通的文本靶瘸,輸出為$monkey$.再如為了在后加上美元符號(占位符恰好又是美元符號)可以用這倆種方式hello,it’s $money$$, 或者Hello,it’s $money+"$"$ 。如果要輸出\符號本生尖淘,則需要用倆個\,這點與javascript奕锌,java 語義一致.