本文旨在解決在使用apache Freemarker模板引擎時遇到的NonHashException,該異常通常發生在嘗試訪問字符串屬性時,提示期望一個哈希值卻得到了字符串。文章將詳細解釋Freemarker中字符串比較的正確方法,并提供示例代碼,幫助開發者避免類似錯誤,提高模板開發效率。
在使用Freemarker模板引擎時,開發者可能會遇到freemarker.core.NonHashException異常,特別是當處理字符串比較時。這個異常通常表明Freemarker期望一個哈希(類似于Java中的map或對象),但實際卻得到了一個字符串。本文將深入探討這個問題,并提供解決方案。
問題分析
在Java代碼中,使用.equals()方法比較字符串的內容是很常見的做法。然而,在Freemarker模板中,情況有所不同。Freemarker對字符串的處理方式與Java有所區別,直接使用.equals()方法可能會導致NonHashException。
考慮以下示例,假設有一個名為previousSearch的對象,其中包含一個名為status的字符串屬性:
import lombok.Data; @Data public class TicketSearchForm { private String status = "ALL"; //More fields... }
在Freemarker模板中,嘗試使用.equals()方法進行字符串比較:
<select name="status" id="status" class="form-control select2"> <option value="ALL" <#if previousSearch.getStatus().equals("ALL")>selected</#if>>Alle anzeigen</option> <option value="OPEN" <#if previousSearch.status.equals("OPEN")>selected</#if>>Offen</option> <option value="DONE" <#if previousSearch.status.equals("DONE")>Geschlossen</option> </select>
這段代碼可能會拋出NonHashException,因為Freemarker不推薦使用.equals()方法進行字符串比較。
解決方案
在Freemarker中,應該使用==運算符來比較字符串。這與Java中比較對象引用是否相等不同,在Freemarker中,==運算符用于比較字符串的內容是否相等。
修改上面的示例代碼,使用==運算符進行字符串比較:
<select name="status" id="status" class="form-control select2"> <option value="ALL" <#if previousSearch.status == "ALL">selected</#if>>Alle anzeigen</option> <option value="OPEN" <#if previousSearch.status == "OPEN">selected</#if>>Offen</option> <option value="DONE" <#if previousSearch.status == "DONE">Geschlossen</option> </select>
通過將.equals()替換為==運算符,可以避免NonHashException,并正確地比較字符串的內容。
示例代碼
以下是一個更完整的示例,展示了如何在spring mvc中使用Freemarker進行字符串比較:
Java Controller:
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class TicketController { @GetMapping("/search") public String search(Model model) { TicketSearchForm previousSearch = new TicketSearchForm(); previousSearch.setStatus("OPEN"); // 設置初始狀態 model.addAttribute("previousSearch", previousSearch); return "ticket/search"; } }
Freemarker Template (ticket/search.ftlh):
<!DOCTYPE html> <html> <head> <title>Ticket Search</title> </head> <body> <h1>Ticket Search Form</h1> <select name="status" id="status" class="form-control select2"> <option value="ALL" <#if previousSearch.status == "ALL">selected</#if>>Alle anzeigen</option> <option value="OPEN" <#if previousSearch.status == "OPEN">selected</#if>>Offen</option> <option value="DONE" <#if previousSearch.status == "DONE">Geschlossen</option> </select> </body> </html>
在這個例子中,Controller將TicketSearchForm對象傳遞給Freemarker模板。模板使用==運算符比較previousSearch.status屬性與不同的字符串值,從而正確地設置
注意事項
-
空值處理: 在進行字符串比較之前,確保要比較的字符串不為空。可以使用Freemarker的?has_content指令來檢查變量是否為空。
<#if previousSearch.status?? && previousSearch.status == "OPEN"> ... </#if>
-
大小寫敏感: Freemarker的字符串比較是大小寫敏感的。如果需要進行大小寫不敏感的比較,可以使用?lower_case或?upper_case指令將字符串轉換為統一的大小寫形式。
<#if previousSearch.status?lower_case == "open"> ... </#if>
總結
在使用Freemarker模板引擎時,理解其字符串比較的特殊性至關重要。通過使用==運算符而不是.equals()方法,可以避免NonHashException,并正確地進行字符串比較。此外,注意空值處理和大小寫敏感性,可以編寫出更健壯、更可靠的Freemarker模板。掌握這些技巧將有助于提高模板開發效率,并減少潛在的錯誤。