性能排名第一的模板引擎 JTE 在 Spring Boot 中的應用
1. 簡介
模板引擎是為了解決用戶界面(顯示)與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,如HTML、XML等。常見的模板引擎有FreeMarker和Thymeleaf等。
FreeMarker通過特定的語法,如${參數},將數據注入模板中,實現動態內容的生成。它適用于生成復雜格式的Excel文件、PDF文檔等。
Thymeleaf則提供標準和Spring標準兩種方言,可以直接套用模板實現JSTL、OGNL表達式效果。它特別適用于與SpringMVC集成的項目。
JTE(Java Template Engine)是一個輕量級的模板引擎,專為Java應用設計。它采用了獨特的DSL(領域特定語言)來簡化模板編寫過程,使得模板更加簡潔易讀。JTE支持強大的繼承和組合機制,這不僅有助于構建復雜的頁面結構,還能有效減少重復代碼。此外,JTE還提供了良好的錯誤報告功能,幫助開發者快速定位和解決問題,提高了開發效率。總之,無論是小型網站還是大型企業級應用,JTE都能提供靈活且高效的解決方案,是值得嘗試的一款模板引擎。
JTE性能
按設計,jte 提供了非常快的輸出速度。這是一個包含了 jte 的 mbosecke/template-benchmark 的分支版本,在 AMD Ryzen 5950X(單線程)上運行。
圖片
mbosecke/template-benchmark github地址如下:https://github.com/casid/template-benchmark/
高并發
這是與上面相同的基準測試,但線程數被設置為@Threads(16),以充分利用所有核心。jte幾乎沒有序列化瓶頸,并且在具有多個CPU核心的服務器上能夠非常高效地并發運行:
圖片
2. 實戰案例
2.1 快速入門
定義數據模型
public class Page {
private String title ;
private String description ;
// getters, setters
}
定義jte模板
@import com.pack.jte.test.Page
@param Page page
<html>
<head>
<meta charset="UTF-8">
@if(page.getDescription() != null)
<meta name="description" content="${page.getDescription()}">
@endif
<title>${page.getTitle()}</title>
</head>
<body>
<h1>${page.getTitle()}</h1>
<p>歡迎使用JTE模板引擎</p>
</body>
</html>
- @import 直接轉換為 Java 或 Kotlin 的導入語句,在這種情況下,使得 com.pack.jte.test.Page 被模板識別。
- @param Page page 是需要傳遞給此模板的參數。
- @if / @endif 構成了一個條件塊。括號內的內容 (page.getDescription() != null) 是標準的 Java 代碼。
- ${} 將內容寫入底層模板輸出,類似于其他多種模板引擎中的用法。
渲染模板
CodeResolver codeResolver = new DirectoryCodeResolver(Path.of("target/classes/templates/jte")) ;
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html) ;
StringOutput so = new StringOutput();
templateEngine.render("test.jte", new Page("xxxooo", "這里是饃饃社交"), so) ;
System.err.println(so.toString()) ;
控制臺輸出結果
圖片
上面代碼中的TemplateEngine實現有很多,你可根據不同的場景選擇合適的輸出模板。
2.2 模板語法
數據顯示
要在模板中顯示數據,請用 ${} 將其包裹起來:
@import my.Model
@param Model model
Hello ${model.name}!
而對應的模型Model則如下:
package my ;
public class Model {
public String name = "Pack" ;
}
上述模板的輸出將是 Hello Pack!
${} 可用來輸出以下類型:
- String
- Enum
- boolean,byte,short,int,long,float,double,char
- 任意實現了gg.jte.Content的類
注意:出于安全考慮,不會自動進行 .toString() 轉換。不支持的類型會產生編譯錯誤。
if語句塊
你可以使用關鍵字 @if、@elseif、@else 和 @endif 來構造 if 語句。這些關鍵字可直接轉換為 Java 對應的關鍵字:
@if(model.entries.isEmpty())
I have no entries!
@elseif(model.entries.size() == 1)
I have one entry!
@else
I have ${model.entries.size()} entries!
@endif
自 Java 14+ 起,還可以對 instanceof 使用模式匹配:
@if (model instanceof SubModel subModel)
${subModel.getSpecial()}
@endif
就像寫Java代碼一樣。
循環
除了 if 語句,jte 還提供了 @for 和 @endfor 關鍵字,用于循環遍歷可迭代數據。同樣,@for 可以直接轉換為 Java 或 Kotlin 的對應關鍵字:
@for(Entry entry : model.entries)
<li>${entry.title}</li>
@endfor
@for(var entry : model.entries)
<li>${entry.title}</li>
@endfor
@for(int i = 0; i < 10; ++i)
<li>i is ${i}</li>
@endfor
循環時,你可以使用 gg.jte.support.ForSupport 類獲取有關循環的信息,例如你是在循環的第一次迭代還是最后一次迭代。
@import gg.jte.support.ForSupport
@for(var entryLoop : ForSupport.of(model.entries))
<tr class="${(entryLoop.getIndex() + 1) % 2 == 0 ? "even" : "odd"}">
${entryLoop.get()}
</tr>
@endfor
自 jte 3.0 起,可以在 @endfor 之前使用 @else。如果循環中沒有遍歷任何元素,@else 內容就會渲染。這對顯示空列表狀態非常有用,無需額外的 @if。例如
@for(var item : datas)
<tr>
<td>${item.getName()}</td>
<td>${item.getQuantity()}</td>
</tr>
@else
<tr>
<td colspan="2">本月銷售總數</td>
</tr>
@endfor
這功能不錯誤。
注釋
jte 允許你在模板中定義注釋。
<%-- 這里是注釋信息 --%>
注意:模板輸出中不包含 jte 注釋。
模板調用
要在模板之間共享共同功能,可以調用其他模板。所有模板都必須位于 jte 根目錄下。
通用模板定義templates/jte/common.jte
@import com.pack.jte.test.Entry
@param Entry entry
@param boolean verbose
<h2>${entry.getTitle()}</h2>
@if(verbose)
<h3>xxxooo</h3>
@endif
在其它模板中調用該模板。
@template.common(page.getEntry(), false)
這里@template后面是你要調用模板的完整路徑。類似方法調用,該模板中需要什么數據,直接在這里傳入。
模板渲染示例:
CodeResolver codeResolver = new DirectoryCodeResolver(Path.of("target/classes/templates/jte")) ;
TemplateEngine templateEngine = TemplateEngine.create(codeResolver, ContentType.Html) ;
TemplateOutput so = new StringOutput();
Page page = new Page("xxxooo", "這里是饃饃社交");
page.setEntry(new Entry("你好中國")) ;
以上我們介紹了常用的一些語法,還有其它如需要了解可以查看官網。
2.3 在Spring Boot中的應用
我們只需要引入以下的依賴即可,根據你使用Spring Boot的版本,支持2.x、3.x
<dependency>
<groupId>gg.jte</groupId>
<artifactId>jte</artifactId>
<version>3.1.12</version>
</dependency>
<dependency>
<groupId>gg.jte</groupId>
<artifactId>jte-spring-boot-starter-3</artifactId>
<version>3.1.12</version>
</dependency>
配置文件如下配置
gg:
jte:
developmentMode: true
# 生產環境設置,與上面的不能同時設置
usePrecompiledTemplates: false
# 注意這里的路徑,如果你打成的jar運行,則你應該在你當前jar所在目錄同級建立對應的目錄
templateLocation: target/classes/templates/jte
templateSuffix: .jte
設置了模板文件的路徑及文件的后綴。同時設置了當前為開發模式。
我們這里以上面的test.jte為例演示
@Controller
@RequestMapping("/jte")
public class TestController {
@GetMapping("")
public String view(Model model, HttpServletResponse response) {
Page page = new Page("xxxooo", "這里是饃饃社交");
page.setEntry(new Entry("你好中國")) ;
model.addAttribute("page", page);
return "test";
}
}
頁面展示:
圖片
除了要注意模板路徑問題外,其它就像以前一樣該怎么寫就怎么寫,模板數據模型的使用方式都一樣的。