不使用 Spring MVC 的 Thymeleaf

最後更新: 2026-05-10 10:03:32 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

即使不使用 Spring MVC,Thymeleaf 也能在批次工作、命令列程式、郵件服務或報表管線中呈現 HTML。獨立應用程式會設定範本解析器和 TemplateEngine,提供內容環境,並將呈現後的輸出寫入目的地。

選擇整合層級 #

非 Spring 程式需要 Thymeleaf 核心構件:

xml
<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf</artifactId>
  <version>3.1.3.RELEASE</version>
</dependency>

Spring 應用程式可以使用 thymeleaf-spring6 和 SpringTemplateEngine,以支援 Spring EL、MessageSource、轉換,以及感知 Spring 的連結行為。Spring Boot 的相依性管理應選擇相符的 Thymeleaf 版本。需要這些整合功能時,spring-boot-starter-thymeleaf 很方便,但執行核心引擎並不需要它,也不需要 MVC。

設定解析器和引擎 #

選擇符合範本管理方式的解析器。ClassLoaderTemplateResolver 適合封裝在 JAR 中且不可變更的範本;FileTemplateResolver 適合由操作人員管理的檔案:

java
var resolver = new ClassLoaderTemplateResolver();
resolver.setPrefix("reports/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
resolver.setCacheable(true);

var engine = new TemplateEngine();
engine.setTemplateResolver(resolver);

引擎應設定一次,然後共用。Thymeleaf 文件將完整設定的 TemplateEngine 說明為具備執行緒安全性;但在開始處理後變更設定並不受支援。對於穩定的正式環境範本,請啟用快取。只有在開發或操作期間必須重新讀取檔案時,才停用快取,或設定有效期受限的快取。

解析器上的字元編碼控制範本位元組的解碼方式。輸出 Writer 使用的編碼則獨立控制產生檔案的位元組,因此請明確設定兩者。

呈現異質的報表資料 #

不要在 Java 中建構 HTML,而應公開符合領域模型形狀的值:

java
record WarningRow(String orderId, String message) {}
record DailyReport(List<OrderSummary> orders, List<WarningRow> warnings) {}

var context = new Context(Locale.ENGLISH);
context.setVariable("report", report);
context.setVariable("generatedAt", generatedAt);
engine.process("daily-report", context, writer);

範本可以呈現包含不同資料列型別的獨立區段:

html
<section>
  <h2>Warnings</h2>
  <table>
    <tr th:each="warning : ${report.warnings}">
      <td th:text="${warning.orderId}">order</td>
      <td th:text="${warning.message}">message</td>
    </tr>
  </table>
</section>

th:text 會依據輸出模式逸出文字。th:utext 會輸出未逸出的標記,因此不得接收不受信任的內容。HTML 範本模式會解析並寫出具備 HTML 感知能力的標記;只有在目標格式需要不同規則時,才選擇 XML、text、JavaScript 或 CSS 模式。

片段和可測試性 #

使用 th:fragment 宣告可重複使用的標記,並透過 th:insert 或 th:replace 組合。片段參數可以讓共用表格和標頭不依賴全域變數名稱。多個解析器可以排序,並透過可解析模式限制範圍,避免過於寬泛的檔案系統解析器無意間遮蔽已封裝的範本。

將呈現維持為接收報表模型和 Writer 的純服務。測試可以使用 StringWriter,以 HTML 解析器剖析結果,並驗證結構和逸出行為。解析器測試也應驗證範本不存在及非 ASCII 內容的情況。

管理輸出資源 #

使用明確的字元集寫入,並關閉 writer:

java
Path temporary = Files.createTempFile(outputDirectory, "daily-", ".html");
try (Writer writer = Files.newBufferedWriter(
        temporary, StandardCharsets.UTF_8,
        StandardOpenOption.TRUNCATE_EXISTING)) {
    engine.process("daily-report", context, writer);
}
Files.move(temporary, destination,
    StandardCopyOption.ATOMIC_MOVE,
    StandardCopyOption.REPLACE_EXISTING);

需要原子移動時,請在目的地檔案系統中建立暫存檔案。呈現或上傳失敗後清理暫存路徑,並且在處理成功前不要發布目的地檔案。對於物件儲存,請呈現至有界緩衝區,或透過明確定義重試和部分失敗行為的上傳 API 進行串流上傳。

主要參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)