第一段引用上面的摘要
本文旨在解決在使用 apache Freemarker 模板引擎時遇到的 NonHashException 異常,該異常通常發生在嘗試訪問對象屬性時,Freemarker 卻將對象識別為字符串。通過分析問題原因和提供解決方案,幫助開發者正確地在 Freemarker 模板中訪問和使用對象屬性,避免類型不匹配導致的錯誤。
在使用 spring Boot 和 Apache Freemarker 構建 Web 應用時,經常需要將 Java 對象傳遞到 Freemarker 模板中進行渲染。然而,有時會遇到 freemarker.core.NonHashException 異常,提示 “Expected a hash, but this has evaluated to a String”。 這通常發生在試圖通過點號(.)訪問對象屬性時,Freemarker 引擎錯誤地將該對象識別為字符串。
問題分析
Freemarker 模板引擎對數據類型的處理與 Java 有所不同。當你在模板中使用點號(.)訪問對象屬性時,Freemarker 期望左側的操作數是一個哈希表(Hash),也就是一個可以像 map 一樣通過鍵值對訪問數據的對象。 如果 Freemarker 認為左側的操作數是一個字符串,就會拋出 NonHashException 異常。
例如,假設你有一個 Java 類 TicketSearchForm,包含一個 status 屬性:
import lombok.Data; @Data public class TicketSearchForm { private String status = "ALL"; //More fields... }
你將 TicketSearchForm 對象 previousSearch 傳遞到 Freemarker 模板中,并嘗試使用以下代碼進行比較:
<#if previousSearch.status.equals("ALL")>selected</#if>
這段代碼在 Java 中是完全有效的,但是在 Freemarker 中卻可能拋出 NonHashException 異常。
解決方案
問題的根源在于 Freemarker 處理字符串的方式與 Java 不同。在 Freemarker 中,字符串比較應該使用 == 運算符,而不是 equals() 方法。
因此,正確的 Freemarker 代碼應該如下所示:
<#if previousSearch.status == "ALL">selected</#if>
將 equals() 方法替換為 == 運算符后,Freemarker 就可以正確地比較字符串,避免 NonHashException 異常。
示例代碼
以下是一個完整的示例,展示了如何在 Freemarker 模板中使用 == 運算符比較字符串:
在這個例子中,previousSearch.status 屬性的值將與 “ALL”、”OPEN” 和 “DONE” 進行比較,如果匹配,則對應的
注意事項
- 字符串比較: 在 Freemarker 中,始終使用 == 運算符進行字符串比較,而不是 equals() 方法。
- 對象屬性訪問: 確保傳遞到 Freemarker 模板中的對象屬性是可訪問的,并且具有正確的類型。
- 數據模型: 仔細檢查傳遞到 Freemarker 模板中的數據模型,確保包含所有需要的屬性,并且屬性名稱正確。
- 異常信息: 仔細閱讀 Freemarker 拋出的異常信息,通常可以提供有關問題的線索。
總結
NonHashException 異常是 Freemarker 中常見的錯誤,通常是由于字符串比較方式不正確導致的。通過使用 == 運算符代替 equals() 方法,可以有效地解決這個問題。此外,還需要注意對象屬性的訪問權限和數據模型的正確性,以確保 Freemarker 模板能夠正確地渲染數據。理解 Freemarker 的數據類型處理方式,是避免此類問題的關鍵。