本次回歸碼壇為小夥伴們帶來的是重新定義過的 Template Engine 將極速開發繼續貫徹到 View 層。
Java 模板引擎界已被 Freemarker、Velocity 統治多年,但其在這些年的發展可謂乏善可陳,究其根本原因是因為這個領域嚴重依賴於第三方工具去做詞法、語法分析以及 AST 的構建,並未真正在語言層面進行過深入的追問。
例如 Freemarker、Velocity 是基於 javacc 做的二次開發,其他 java 模板引擎多數也是基於 ANTLR、jflex、javacc 生成後的代碼做的二次開發全部自己動手寫代碼而不是二次開發的 java 模板引擎極為少見,國內較為知名的僅見 HTTL。
由於使用 ANTLR 等工具去做模板引擎可以讓 80% 以上的工作由工具代為完成,所以對模板引擎作者極具誘惑力,但誘惑的背後其實是巨大的陷阱。
首先,這類工具無一例外都要求使用一套特定規則先表示出詞法和語法,然後再把它們生成為 Parser 原始碼而詞法、語法描述用的規則和生成的 Parser 並沒有很強的語義連接關係,如果生成的 Parser 有 bug,非常難以回溯排錯。
其次,生成的 Parser 源碼,毫無可讀性而言,進而在 Parser 層面根本無法調試,這種構建模板引擎的方式,相當於將自己的代碼建立在一個飄搖不安的基礎之上。
再次,通過這種方式做出來的模板引擎如果要在更底層改進,則需要先去改語法、詞法描述規則文件,然後再生成一次 Parser 源碼,然後才可以開始真正寫代碼,這個重複、麻煩且容易出錯的過程也嚴重阻礙了模板引擎的改進。
最後,這種構建方式通常在運行時還需要一個類似於 runtime.jar 的依賴,這個依賴多多少少也會增加不確定的風險。
模板引擎在本質上是一門程序語言,要開發一門可用於生產環境的模板語言起碼要對開發程序語言的相關技術、算法很熟悉,例如常用詞法分析算法、語法分析算法、AST、解釋器、編譯原理等等領域知識。
但非常不幸的是,即便對已有算法很熟悉,仍然只能做出極為平庸的模板引擎,因為模板引擎所處理的對象與程序語言有著十分不同的特徵:模板的內容通常是極其自由的文本中嵌入著少量程序語言元素,而類似於 NFA 這樣的算法都是面向類似於 java、c、python 這類高度結構化的原始碼內容。
JFinal Template Engine 直面這個問題,採用獨創的算法徹底代替傳統算法,極大降低了複雜度,減少了代碼量,同時可讀性得到極大提升。JFinal Template Engine 經過公司內部開發者近三個月的試用時間,直到每位開發者都沉醉其中後才放出 jfinal 3.0 版本。
1:獨創 DKFF(Dynamic Key Feature Forward) 詞法分析算法
傳統的 NFA 詞法分析算法基於正則表達式與狀態圖,即便是做一個簡單的模板引擎也需要成百上千個狀態,NFA 算法對於人類來說幾乎不可讀,需要先將二維數組表示的狀態圖存儲結構轉換成畫在紙上的人類可讀的狀態圖,並且還要花費相當長的時間去解讀其內涵。而 JFinal Template Engine 只需 7 個狀態 403 行代碼搞定詞法分析,可讀高,有利於系統進化。
2:獨創 DLRD(Double layer Recursive Descent) 語法分析算法
針對模板文件大量純文本摻雜少量代碼特徵,獨創 DLRD 語法分析算法,將指令與表達式的語法分析劃分在不同的層次之中相比傳統遞歸下降語法分析算法,複雜度降到極致,代碼量少到極致僅 215 行代碼搞定 statement 語法分析。
DLRD 算法還極為輕鬆地解決了傳統算法面對的左遞歸、二義性、回溯以及運算符優先級等麻煩問題,無需文法變換即可消除左遞歸,無需回溯即可解決二義性問題傳統遞下降法算法需要採用變換文法、回溯、提取公因子方式解決上述問題傳統解決方案不僅麻煩而且讓文法變換後的程序可讀性降低,不利於進化。
3:獨創語言級指令擴展
對於傳統模板引擎來說指令系統是固定的,相當於程序語言的關鍵字,無法為語言動態添加新的關鍵字,JFinal template engine 得益於獨創的 DKFF、DLRD 算法,極為輕鬆的在程序語言層面實現了指令擴展功能,從而整個模板引擎只需提供了極少的常用指令,其她所有指令均由擴展而成,例如 com.jfinal.template.ext.directive 以及com.jfinal.plugin.activerecord.sql 包之下的所有指令全是擴展而來。
基於以上主要創新, JFinal 在極簡的路上繼續挺進,一個 MVC + ORM 各層全面實現極速開發的框架由此誕生:
1:極簡設計
JFinal Template Engine 消滅了大量傳統模板引擎中的無聊概念,例如 macro、layout、pageContent、nested、tag 插值等等概念,但凡一門可用於生產環境的語言,只需利用表達式、語句、函數、分支、循環等基本要素,就可以像呼吸空氣一樣自由地實現上述這些功能,引入新的概念純屬製造麻煩。
以 macro 為例,該概念產生於很古老的程序語言,已證明是歷史性糟粕在後起的程序語言中被拋棄,可卻在 freemarker、velocity 等模板引擎中死而復生,以致於後來者也爭相跟風模仿引入了 macro 概念。
2:獨創空合安全取值調用操作符
JFinal Template Engine 引入了 swift 與 C#語言中的空合操作符,並在其基礎之上進行了極為自然的擴展,該表達式符號為兩個緊靠的問號: ??
value ?? rightExpr // 當value為null時,表達式取值rightExprobject.value ?? // 當 object 為 null 時變為安全取值,不報空指針異常,表達式的值為nullobject.method() ?? // 當 object 為 null 時變為安全調用,不報空指針異常,表達式的值為nullobject.value ?? rightExpr // 空合併與安全取值的組合用法,當object為null時表達式取值rightExprobject.method() ?? rightExpr // 空合併安全調用的組合用法,當object為null時表達式取值為rightExpr
swift 與 C# 語言僅支持第一種用法並稱之為空合操作符,而 JFinal Template Engine 在空合的基礎上再支持安全取值、安全調用兩個擴展,在模板引擎的應用場景之下的開發體驗極為順滑。
3:消滅插值指令
傳統模板引擎通常會引入所謂的插值指令,而其它指令則使用另一套規則,而 jfinal template engine 將插值指令仍然當成是指令,並不引進新的概念,不僅在實現上更加簡潔只需 21 行代碼,而且降低了學習成本
#(value) #(object.value) #(map.key)
4:消滅 macro 指令
如果真心將 template engine 當成一門語言去設計,原本用 macro 實現的功能只需要使用所有語言中都有的 function/method 概念,即可更為簡單實現,如下是利用 fcuntion 實現 layout 功能的示例先在 layout.html 中定義 layout() 函數,並在 body調用 main() 函數
#define layout() <html> <body> #@main() <body> </html> #end
然後在最終的頁面,直接調用 layout() 並定義 main() 函數
#@layout() #define main() ... #end
注意:以上的 layout.html、layout、main 這些名稱可以隨便取名,不是具體的概念,僅為一個名字
JFinal Template Engine 代碼僅有 5556 行,僅為 freemarker 的十分之一,完全手寫算法,無第三方依賴,對於有任何一門程序語言的開發者學習成本幾乎為 0。為控制篇幅,在此不在贅述。jfinal 3.0 版不僅僅是重新定義了 Template Engine,還對其她方面做了非常有價值的改進
1:Routes 級攔截器
jfinal 3.0 可以在 Routes 中添加攔截器,Routes 極攔截器,將攔截所有在此 Routes 中映射的 Controller:
public class AdminRoutes extends Routes { public void config() { addInterceptor(new AdminInterceptor()); add("/admin", IndexAdminController.classs); add("/admin/project", ProjectAdminController.classs); }}
上例中的 AdminInterceptor 將攔截 IndexAdminController、ProjectAdminController 中的所有 action,這非常有利於多個控制器配置了相同攔截器的應用場景,減少了代碼冗餘。
2:active record 模塊 sql 管理模塊
JFinal 3.0利用自帶的Template Engine極為簡潔的實現了Sql管理功能,可以將sql保存在外部配置文件之中,並且以極少概念極少 API 實現 mybatis 的核心功能
#sql("findPrettyGirl") select * from girl where age > ? and age < ? and weight < 50#end
java 代碼中的使用方式:
find(getSql("findPrettyGirl"), 16, 20);
同時還提供了 namespace 支持與 para 動態綁定功能,詳見 jfinal 手冊
3:Cron4jPlugin 支持任務調度
Cron4jPlugin 對 cron4j 進行了極簡封裝,簡單用法如下:
Cron4jPlugin cp = new Cron4jPlugin();cp.addTask("* * * * *", new MyTask());me.add(cp);
外部配置文件用法詳見 jfinal 手冊
4:renderQrCode 支持二維碼生成
添加 Controller.renderQrCode(...) 極速生成二維碼
jfinal 3.0 一如既往地堅持極簡設計風格,在極速開發的路上一路挺進,力爭為開發者帶來更高的開發效率,更好的開發體驗,更低的學習成本,進一步節約時間去陪戀人、家人和朋友!篇幅所限,更多功能增強與改進詳見 changelog: http://www.jfinal.com/share/190
ONE MORE THING:JFinal 俱樂部頻道今起正式開放,將為小夥伴們提供更高附加值的產品與服務進一步提升開發效率,節省開發時間。老司機要發車了,GO GO GO:http://www.jfinal.com/club