1. 什麼是Beetl
Beetl目前版本是2.2.8,相對於其餘java模板引擎,具備功能齊全,語法直觀,性能超高,以及編寫的模板容易維護等特色。使得開發和維護模板有很好的體驗。是新一代的模板引擎。總得來講,它的特性以下:javascript
-
功能完備:做爲主流模板引擎,Beetl具備至關多的功能和其餘模板引擎不具有的功能。適用於*各類應用場景*,從對響應速度有很高要求的大網站到功能繁多的CMS管理系統都適合。Beetl自己還具備不少獨特功能來完成模板編寫和維護,這是其餘模板引擎所不具備的。css
-
很是簡單:相似Javascript語法和習俗,只要半小時就能經過半學半猜徹底掌握用法。拒絕其餘模板引擎那種非人性化的語法和習俗。同時也能支持html 標籤,使得開發CMS系統比較容易html
-
超高的性能:Beetl 遠超過主流java模板引擎性能(引擎性能5-6倍與freemaker,2倍於JSP。參考附錄),並且消耗較低的CPU前端
-
易於整合:Beetl能很容易的與各類web框架整合,如Spring MVC,JFinal,Struts,Nutz,Jodd,Servlet等。java
-
支持模板單獨開發和測試,即在MVC架構中,即便沒有M和C部分,也能開發和測試模板。git
-
擴展和個性化:Beetl支持自定義方法,格式化函數,虛擬屬性,標籤,和HTML標籤. 同時Beetl也支持自定義佔位符和控制語句起始符號也支持使用者徹底能夠打造適合本身的工具包.程序員
2. 基本用法
2.1. 從GroupTemplate開始
1 2 3 4 5 6 7 |
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,建立GroupTemplate須要倆個參數,一個是模板資源加載器,一個是配置類,模板資源加載器Beetl內置了4種,分別是
-
StringTemplateResourceLoader:字符串模板加載器,用於加載字符串模板,如本例所示
-
FileResourceLoader:文件模板加載器,須要一個根目錄做爲參數構造,,傳入getTemplate方法的String是模板文件相對於Root目錄的相對路徑
-
ClasspathResourceLoader:文件模板加載器,模板文件位於Classpath裏
-
WebAppResourceLoader:用於webapp集成,假定模板根目錄就是WebRoot目錄,參考web集成章
-
MapResourceLoader : 能夠動態存入模板
代碼第5行將變量name傳入模板裏,其值是「Beetl」。 代碼第6行是渲染模板,獲得輸出,template提供了多種得到渲染輸出的方法,以下
-
tempalte.render() 返回渲染結果,如本例所示
-
template.renderTo(Writer) 渲染結果輸出到Writer裏
-
template.renderTo(OutputStream ) 渲染結果輸出到OutputStream裏
2.2. 模板基礎配置
Beetl提供不但功能齊全,並且還有不少獨特功能,經過簡單的配置文件,就能夠定義衆多的功能,默認狀況下,Configuration類老是會先加載默認的配置文件(位於/org/beetl/core/beetl-default.properties,做爲新手,一般只須要關注3,4,5,6行定界符的配置,以及11行模板字符集的配置就能夠了,其餘配置會在後面章節陸續提到)下,其內容片段以下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#默認配置
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= /
#是否檢測文件變化
RESOURCE.autoCheck= true
#自定義腳本方法文件的Root目錄和後綴
RESOURCE.functionRoot = functions
RESOURCE.functionSuffix = html
#自定義標籤文件Root目錄和後綴
RESOURCE.tagRoot = htmltag
RESOURCE.tagSuffix = tag
##### 擴展 ##############
## 內置的方法
FN.date = org.beetl.ext.fn.DateFunction
......
##內置的功能包
FNP.strutil = org.beetl.ext.fn.StringUtil
......
##內置的默認格式化函數
FTC.java.util.Date = org.beetl.ext.format.DateFormat
.....
## 標籤類
TAG.include= org.beetl.ext.tag.IncludeTag
|
第2行配置引擎實現類,默認便可.
第3,4行指定了佔位符號,默認是${ }.也能夠指定爲其餘佔位符。
第5,6行指定了語句的定界符號,默認是<% %>,也能夠指定爲其餘定界符號
第7行指定IO輸出模式,默認是FALSE,即一般的字符輸出,在考慮高性能狀況下,能夠設置成true。詳細請參考高級用法
第8,9行指定了支持HTML標籤,且符號爲#,默認配置下,模板引擎識別<#tag ></#tag>這樣的相似html標籤,並能調用相應的標籤函數或者模板文件。你也能夠指定別的符號,如bg: 則識別<bg:
第10行 指定若是標籤屬性有var,則認爲是須要綁定變量給模板的標籤函數
第11行指定容許本地Class直接調用
第12行指定模板字符集是UTF-8
第13行指定異常的解析類,默認是ConsoleErrorHandler,他將在render發生異常的時候在後臺打印出錯誤信息(System.out)。
第14行指定了本地Class調用的安全策略
第15行配置了是否進行嚴格MVC,一般狀況下,此處設置爲false.
第18行指定了默認使用的模板資源加載器
第20到22行配置了模板資源加載器的一些屬性,如設置根路徑爲/,即Classpath的頂級路徑,而且老是檢測模板是否更改
第23行配置了自定義的方法所在的目錄以及文件名後綴。beetl既支持經過java類定義方法,也支持經過模板文件來定義方法
第26行配置了自定義的html標籤所在的目錄以及文件名後綴。beetl既支持經過java類定義標籤,也支持經過模板文件來定義標籤
第31行註冊了一個date方法,其實現類是org.beetl.ext.fn.DateFunction
第34行註冊了一個方法包strutil,其實現類org.beetl.ext.fn.StringUtil,此類的每一個public方法都將註冊爲beetl的方法
第37行註冊了一個日期格式化函數
第40行註冊了一個include標籤函數
2.3. 模板資源加載器
資源加載器是根據String值獲取Resource實例的工場類,同時資源加載器還要負責響應模板引擎詢問模板是否變化的調用。對於新手來講,無需考慮模板資源加載器如何實現,只須要根據本身場景選擇系統提供的三類模板資源加載器便可
2.3.1. 字符串模板加載器
在建立GroupTemplate過程當中,若是傳入的是StringTemplateResourceLoader,則容許經過調用gt.getTemplate(String template)來獲取模板實例對象,如2.1所示
2.3.2. 文件資源模板加載器
更一般狀況下,模板資源是以文件形式管理的,集中放在某一個文件目錄下(如webapp的模板根目錄就多是WEB-INF/template裏),所以,可使用FileResourceLoader來加載模板實例,以下代碼:
1 2 3 4 5 6 7 |
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.3.3. Classpath資源模板加載器
還有種常狀況下,模板資源是打包到jar文件或者同Class放在一塊兒,所以,可使用ClasspathResourceLoader來加載模板實例,以下代碼:
1 2 3 4 5 6 |
ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(); Configuration cfg = Configuration.defaultConfiguration(); GroupTemplate gt = new GroupTemplate(resourceLoader, cfg); Template t = gt.getTemplate("/org/beetl/sample/s01/hello.txt"); String str = t.render(); System.out.println(str);
|
第1行代碼指定了模板根目錄,即搜索模板的時候從根目錄開始,若是new ClasspathResourceLoader("/template"),則表示搜索/template下的模板。此處用空構造函數,表示搜索路徑是根路徑,且字符集默認字符集UTF-8.
第4行經過模板的相對路徑org/beetl/sample/s01/hello.txt來加載模板
2.3.4. WebApp資源模板加載器
WebAppResourceLoader 是用於web應用的資源模板加載器,默認根路徑是WebRoot目錄。也能夠經過制定root屬性來設置相對於WebRoot的的模板根路徑,從安全角考慮,建議放到WEB-INF目錄下
以下是Jfinal集成 裏初始化GroupTemplate的方法
1 2 3 |
Configuration cfg = Configuration.defaultConfiguration(); WebAppResourceLoader resourceLoader = new WebAppResourceLoader(); groupTemplate = new GroupTemplate(resourceLoader, cfg);
|
2.3.5. 自定義資源模板加載器
有時候模板可能來自文件系統不一樣目錄,或者模板一部分來自某個文件系統,另一部分來自數據庫,還有的狀況模板多是加密混淆的模板,此時須要自定義資源加載,繼承ResouceLoader才能實現模板功能,這部分請參考高級部分
2.4. 定界符與佔位符號
Beetl模板語言相似JS語言和習俗,只須要將Beetl語言放入定界符號裏便可,如默認的是<% %> ,佔位符用於靜態文本里嵌入佔位符用於輸出,以下是正確例子
1 2 3 4 5 6 |
<%
var a = 2; var b = 3; var result = a+b; %> hello 2+3=${result}
|
千萬不要在定界符裏使用佔位符號,由於佔位符僅僅嵌在靜態文本里,以下例子是錯誤例子
1 2 3 4 |
<%
var a = "hi"; var c = ${a}+"beetl"; //應該是var c = a+"beetl" %>
|
每次有人問我如上例子爲啥不能運行的時候,我老是有點憎惡velocity 帶來的這種非人性語法
定界符號裏是表達式,若是表達式跟定界符有衝突,能夠在表達式裏用 「\」 符號,如
1 2 |
${[1,2,3]} //輸出一個json列表 ${ {key:1,value:2 \} } //輸出一個json map,} 須要加上\
|
定界符和佔位符 一般還有別的選擇,以下定界符
-
@ 和回車換行 (此時,模板配置DELIMITER_STATEMENT_END= 或者 DELIMITER_STATEMENT_END=null 均可以)
-
#: 和回車換行
-
<!--: 和 -→
-
<!--# 和 -→
-
<? 和 ?>
佔位符: - - #{ } - # #
你也能夠與團隊達成一致意見來選擇團隊喜好擇定界符號和佔位符號。
2.5. 註釋
Beetl語法相似js語法,因此註釋上也同js同樣: 單行註釋採用//
多行注視採用/**/
1 2 3 4 5 6 7 8 |
<%
/*此處是一個定義變量*/ var a = 3; //定義一個變量. /* 如下內容都將被註釋 %> <% */ %>
|
第2行是一個多行註釋
第3行是一個單行註釋
第5行到第8行採用的是多行註釋,所以裏面有內容也是註釋,模板將不予處理
2.6. 臨時變量定義
在模板中定義的變量成爲臨時變量,這相似js中採用var 定義的變量,以下例子
1 2 3 4 5 6 7 8 |
<%
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.7. 全局變量定義
全局變量是經過template.binding傳入的變量,這些變量能在模板的任何一個地方,包括子模板都能訪問到。如java代碼裏
1 2 3 4 5 6 7 8 |
template.binding("list",service.getUserList()); //在模板裏 <% for(user in list){ %> hello,${user.name}; <%}%>
|
2.8. 共享變量
共享變量指在全部模板中均可以引用的變量,可過groupTemplate.setSharedVars(Map<String, Object> sharedVars)傳入的變量,這些變量能在 全部模板 的任何一個地方
1 2 3 4 5 6 7 8 9 10 11 |
.....
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);
|
1 2 3 4 |
//t1.txt
hi,${name} //t2.txt hello,${name}
|
2.9. 模板變量
模板變量是一種特殊的變量,便可以將模板中任何一段的輸出賦值到該變量,並容許稍後在其餘地方使用,以下代碼
1 2 3 4 5 6 7 8 |
<%
var content = { var c = "1234"; print(c); %> 模板其餘內容: <%}; %>
|
第2行定義了一個模板變量content = { …} ; 此變量跟臨時變量同樣,能夠在其餘地方使用,最多見的用戶是用於複雜的佈局。請參考高級用法佈局
2.10. 引用屬性
屬性引用是模板中的重要一部分,beetl支持屬性引用若是javascript的支持方式同樣,以下
1 Beetl支持經過」.」號來訪問對象的的屬性,若是javascript同樣。若是User對象有個getName()方法,那麼在模板中,能夠經過${xxx.name}來訪問
2 若是模板變量是數組或者List類,這能夠經過[] 來訪問,如${userList[0]}
3 若是模板變量是Map類,這能夠經過[]來訪問,如${map[「name」]},若是key值是字符串類型,也可使用${map.name}.但不建議這麼使用,由於會讓模板閱讀者誤覺得是一個Pojo對象
4 Beetl也支持Generic Get方式,即若是對象有一個public Object get(String key)方法,能夠經過」.」號或者[]來訪問,譬如 ${activityRecord.name}或者${activityRecord[「name」] }都將調用activityRecord的 get(String key)方法。若是對象既有具體屬性,又有Generic get(這種模型設計方式是不值得鼓勵),則以具體屬性優先級高.
5 Beetl也能夠經過[]來引用屬性,如${user[「name」]} 至關於${user.name}.這跟javascript保持一致。但建議不這麼作,由於容易讓閱讀模板的人誤認爲這是一個Map類型
6 Beetl 還能夠定位額外的對象屬性,而無需更改java對象,這叫着虛擬屬性,如,對於全部集合,數組,都有共同的虛擬熟悉size.虛擬屬性是「.~」+虛擬1屬性名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
template.binding("list",service.getUserList()); template.binding("pageMap",service.getPage()); //在模板裏 總共 ${list.~size} <% for(user in list){ %> hello,${user.name}; <%}%> 當前頁${pageMap['page']},總共${pageMap["total"]}
|
2.11. 算數表達式
Beetl支持相似javascript的算術表達式和條件表達式,如+ - * / % 以及(),以及自增++,自減--
1 2 3 4 5 6 7 8 |
<%
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類型,對於模板經常使用狀況說,已經夠了.若是須要定義長精度類型(對應java的BigDecimal),則須要在數字末尾加上h以表示這是長精度BigDecimal,其後的計算和輸出以及邏輯表達式都將按照長精度類型來考慮。
2.12. 邏輯表達式
Beetl支持相似Javascript,java的條件表達式 如>, <, == ,!=,>= , ⇐ 以及 !, 還有&&和 || ,還有三元表達式等,以下例子
1 2 3 4 5 6 7 8 9 |
<%
var a = 1; var b=="good"; var c = null; if(a!=1&&b=="good"&&c==null){ ...... } %>
|
三元表達式若是隻考慮true條件對應的值的話,能夠作簡化,以下倆行效果是同樣的。
1 2 3 4 5 |
<%
var a = 1 ; %> ${a==1?"ok":''} ${a==1?"ok"}
|
2.13. 循環語句
Beetl支持豐富的循環方式,如for-in,for(exp;exp;exp),以及while循環,以及循環控制語句break;continue; 另外,若是沒有進入for循環體,還能夠執行elsefor指定的語句。
2.13.1. for-in
for-in循環支持遍歷集合對象,對於List和數組來講以及Iterator,對象就是集合對象,對於Map來講,對象就是Map.entry,以下倆個例子
1 2 3 4 5 6 7 |
<%
for(user in userList){ print(userLP.index); print(user.name); } %>
|
第三行代碼userLP是Beetl隱含定義的變量,能在循環體內使用。其命名規範是item名稱後加上LP,他提供了當前循環的信息,如
-
userLP.index :當前的索引,從1開始
-
userLP.size:集合的長度
-
userLP.first 是不是第一個
-
userLP.last 是不是最後一個
-
userLP.even 索引是不是偶數
-
userLP.odd 索引是不是奇數
以下是Map使用例子
1 2 3 4 5 6 7 8 |
<%
for(entry in map){ var key = entry.key; var value = entry.value; print(value.name); } %>
|
2.13.2. for(exp;exp;exp)
對於渲染邏輯更爲常見的是經典的for循環語句,以下例子
1 2 3 4 5 6 |
<%
var a = [1,2,3]; for(var i=0;i<a.~size;i++){ print(a[i]); } %>
|
2.13.3. while
對於渲染邏輯一樣常見的有的while循環語句,以下例子
1 2 3 4 5 6 7 |
<%
var i = 0; while(i<5){ print(i); i++; } %>
|
2.13.4. elsefor
不一樣於一般程序語言,若是沒有進入循環體,則不需額外的處理,模板渲染邏輯更常見狀況是若是沒有進入循環體,還須要作點什麼,所以,對於for循環來講,還有elsefor 用來表達若是循環體沒有進入,則執行elsefor 後的語句
1 2 3 4 5 6 7 8 |
<%
var list = []; for(item in list){ }elsefor{ print("未有記錄"); } %>
|
2.14. 條件語句
2.14.1. if else
同js同樣,支持if else,以下例子
1 2 3 4 5 6 7 8 9 10 11 12 |
<%
var a =true; var b = 1; if(a&&b==1){ }else if(a){ }else{ } %>
|
2.14.2. switch-case
同js同樣,支持switch-case,以下例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<%
var b = 1; switch(b){ case 0: print("it's 0"); break; case 1: print("it's 1"); break; default: print("error"); } %>
|
2.14.3. select-case
select-case 是switch case的加強版。他容許case 裏有邏輯表達式,同時,也不須要每一個case都break一下,默認遇到合乎條件的case執行後就退出。
1 2 3 4 5 6 7 8 9 10 11 12 |
<%
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 後的邏輯表達式將決定執行哪一個case.其格式是
1 2 3 4 5 6 |
select { case boolExp,orBoolExp2: doSomething(); } %>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<%
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.15. try-catch
一般模板渲染邏輯不多用到try-catch 但考慮到渲染邏輯複雜性,以及模板也有不可控的地方,因此提供try catch,在渲染失敗的時候仍然能保證輸出正常
1 2 3 4 5 6 7 8 |
<%
try{ callOtherSystemView() }catch(error){ print("暫時無數據"); } %>
|
error表明了一個異常,你能夠經過error.message 來獲取可能的錯誤信息
也能夠省略catch部分,這樣出現異常,不作任何操做
2.16. 虛擬屬性
虛擬屬性也是對象的屬性,可是虛擬的,非模型對象的真實屬性,這樣的好處是當模板須要額外的用於顯示的屬性的時候但又不想更改模型,即可以採用這種辦法 如beetl內置的虛擬屬性.~size 針對了數組以及集合類型。
1 2 |
${user.gender} ${user.~genderShowName}
|
~genderShowName 是虛擬屬性,其內部實現根據boolean變量gender來顯示性別
如何完成虛擬屬性,請參考高級用法
2.17. 函數調用
Beetl內置了少許實用函數,能夠在Beetl任何地方調用。以下例子是調用date 函數,不傳參數狀況下,返回當前日期
1 2 3 4 5 6 |
<%
var date = date(); var len = strutil.length("cbd"); println("len="+len); %>
|
注意函數名支持namespace方式,所以代碼第3行調用的函數是strutil.length
Beetl內置函數請參考附錄,如下列出了經常使用的函數
-
date 返回一個java.util.Date類型的變量,如 date() 返回一個當前時間(對應java的java.util.Date); ${date( "2011-1-1" , "yyyy-MM-dd" )} 返回指定日期
-
print 打印一個對象 print(user.name);
-
println 打印一個對象以及回車換行符號,回車換號符號使用的是模板自己的,而不是本地系統的.若是僅僅打印一個換行符,則直接調用println() 便可
-
nvl 函數nvl,若是對象爲null,則返回第二個參數,不然,返回本身 nvl(user,"不存在")
-
isEmpty 判斷變量或者表達式是否爲空,變量不存在,變量爲null,變量是空字符串,變量是空集合,變量是空數組,此函數都將返回true
-
isNotEmpty 同上,判斷對象是否不爲空
-
has 變量名爲參數,判斷是否存在此全局變量,如 has(userList),相似於1.x版本的exist("userList"),但不須要輸入引號了
-
assert 若是表達式爲false,則拋出異常
-
trunc 截取數字,保留指定的小數位,如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指定的對象以及所在模板文件以及模板中的行數,如debug(1),則輸出1 [在3行@/org/beetl/core/lab/hello.txt],也能夠輸出多個,如debug("hi",a),則輸出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]
-
parseInt 將數字或者字符解析爲整形 如 parseInt("123");
-
parseLong 將數字或者字符解析爲長整形,parseInt(123.12);
-
parseDouble 將數字或者字符解析爲浮點類型 如parseDouble("1.23")
-
range 接收三個參數,初始值,結束值,還有步增(能夠不須要,則默認爲1),返回一個Iterator,經常使用於循環中,如for(var i in range(1,5)) {print(i)},將依次打印1234.
-
flush 強制io輸出。
-
json,將對象轉成json字符串,如 var data = json(userList) 能夠跟一個序列化規則 如,var data = json(userList,"[*].id:i"),具體參考https://git.oschina.net/xiandafu/beetl-json
-
pageCtx ,僅僅在web開發中,設置一個變量,而後能夠在頁面渲染過程當中,調用此api獲取,如pageCtx("title","用戶添加頁面"),在其後任何地方,能夠pageCtx("title") 獲取該變量
2.18. 安全輸出
安全輸出是任何一個模板引擎必須重視的問題,不然,將極大困擾模板開發者。Beetl中,若是要輸出的模板變量爲null,則beetl將不作輸出,這點不一樣於JSP,JSP輸出null,也不一樣於Feemarker,若是沒有用!,它會報錯.
模板中還有倆種狀況會致使模板輸出異常
-
有時候模板變量並不存在(譬如子模板裏)
-
模板變量爲null,但輸出的是此變量的一個屬性,如${user.wife.name}
針對前倆種種狀況,能夠在變量引用後加上!以提醒beetl這是一個安全輸出的變量。
如${{user.wife.name! },即便user不存在,或者user爲null,或者user.wife爲null,或者user.wife.name爲null beetl都不將輸出
能夠在!後增長一個常量(字符串,數字類型等),或者另一個變量,方法,本地調用,做爲默認輸出,譬如:
${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
還有一種狀況不多發生,但也有可能,輸出模板變量發生的任何異常,如變量內部拋出的一個異常
這須要使用格式${!(變量)},這樣,在變量引用發生任何異常狀況下,都不做輸出,譬如
${!(user.name)},,beetl將會調用user.getName()方法,若是發生異常,beetl將會忽略此異常,繼續渲染
值得注意的是,在變量後加上!不只僅能夠應用於佔位符輸出(但主要是應用於佔位符輸出),也能夠用於表達式中,如:
1 2 3 4 5 6 7 8 |
<%
<% var k = user.name!'N/A'+user.age!; %> ${k} %>
|
若是user爲null,則k值將爲N/A
在有些模板裏,可能整個模板都須要安全輸出,也可能模板的部分須要安全輸出,使用者沒必要爲每個表達式使用!,可使用beetl的安全指示符號來完成安全輸出 如:
1 2 3 4 5 6 7 8 9 |
<%
DIRECTIVE SAFE_OUTPUT_OPEN; %> ${user.wife.name} 模板其餘內容,均能安全輸出…… <% //關閉安全輸出。 DIRECTIVE SAFE_OUTPUT_CLOSE; %>
|
Beetl不建議每個頁面都使用DIRECTIVE SAFE_OUTPUT_OPEN,這樣,若是若是真有不指望的錯誤,不容易及時發現,其次,安全輸出意味着beetl會有額外的代碼檢測值是否存在或者是否爲null,性能會略差點。因此建議及時關閉安全輸出(這不是必須的,但頁面全部地方是安全輸出,可能不容易發現錯誤)
在for-in 循環中 ,也能夠爲集合變量增長安全輸出指示符號,這樣,若是集合變量爲null,也能夠不進入循環體,如:
1 2 3 4 5 6 7 8 |
<%
var list = null; for(item in list!){ }eslefor{ print("no data"); } %>
|
2.18.1. 變量是否存在
判斷變量是否存在,能夠採用內置的has或者isEmpty方法來判斷,參數是變量,如
1 2 3 4 5 |
<%
if(has(flag)){ print("not exit") } %>
|
若是須要判斷變量是否存在,若是存在,還有其餘判斷條件,一般都這麼寫
1 2 3 4 5 |
<%
if(has(flag)||flag==0){ //code } %>
|
若是flag不存在,或者flag存在,但值是0,都將執行if語句
可是,有更爲簡便的方法是直接用安全輸出,如
1 2 3 4 5 |
<%
if(flag!0==0){ //code } %>
|
flag!0 取值是這樣的,若是flag不存在,則爲0,若是存在,則取值flag的值,相似三元表達式 has(flag)?falg:0
2.18.2. 安全輸出表達式
安全輸出表達式能夠包括
-
字符串常量,如 ${user.count!"無結果"}
-
boolean常量 ${user.count!false}
-
數字常量,僅限於正數,由於若是是負數,則相似減號,容易誤用,所以,若是須要表示負數,請用括號,如${user.count!(-1)}
-
class直接調用,如${user.count!@User.DEFAULT_NUM}
-
方法調用,如 ${user.count!getDefault() }
-
屬性引用,如 ${user.count!user.maxCount }
-
任何表達式,須要用括號
2.19. 格式化
幾乎全部的模板語言都支持格式化,Beetl也不列外,以下例子Beetl提供的內置日期格式
1 2 3 4 |
<% var date = date(); %> Today is ${date,dateFormat="yyyy-MM-dd"}. Today is ${date,dateFormat} salary is ${salary,numberFormat="##.##"}
|
格式化函數只須要一個字符串做爲參數放在=號後面,若是沒有爲格式化函數輸入參數,則使用默認值,dateFormat格式化函數默認值是local
Beetl也容許爲指定的java class設定格式化函數,譬如已經內置了對java.util.Date,java.sql.Date 設置了了格式化函數,所以上面的例子能夠簡化爲
1 |
${date,「yyyy-MM-dd」}.
|
Beetl針對日期和數字類型提供的默認的格式化函數,在org/beetl/core/beetl-default.properties裏,註冊了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
##內置的格式化函數 FT.dateFormat = org.beetl.ext.format.DateFormat FT.numberFormat = org.beetl.ext.format.NumberFormat ##內置的默認格式化函數 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 |