本文旨在解決在使用apache Freemarker模板引擎時,遇到的freemarker.core.NonHashException: Expected a hash, but this has evaluated to a String 錯誤,并提供正確的字符串比較方法。該錯誤通常發生在嘗試訪問對象屬性時,Freemarker將其誤判為字符串。通過理解Freemarker的字符串處理方式,可以有效避免此類問題。
問題分析
在使用Freemarker模板引擎進行開發時,當嘗試訪問一個對象的屬性,并進行字符串比較時,可能會遇到NonHashException。例如,在spring mvc項目中,從Controller傳遞一個Java對象到Freemarker模板,并嘗試訪問該對象的string類型的屬性時,可能會出現如下錯誤:
freemarker.core.NonHashException: For "." left-hand operand: Expected a hash, but this has evaluated to a string (wrapper: f.t.SimpleScalar): ==> previousSearch.status [in template "ticket/search.ftlh" at line 22, column 66]
這個錯誤表明Freemarker期望.左邊的操作數是一個Hash(類似于Java中的map),但實際卻是一個字符串。
原因探究
出現這種問題的原因在于Freemarker對字符串的處理方式與Java有所不同。在Java中,我們通常使用.equals()方法來比較字符串的內容。但在Freemarker中,推薦使用==運算符來進行字符串比較。
解決方案
將Freemarker模板中的.equals()方法替換為==運算符即可解決此問題。
例如,將以下代碼:
<option value="ALL" <#if previousSearch.status.equals("ALL")>selected</#if>>Alle anzeigen</option>
修改為:
<option value="ALL" <#if previousSearch.status == "ALL">selected</#if>>Alle anzeigen</option>
通過這種方式,Freemarker可以正確地比較字符串,從而避免NonHashException。
示例代碼
假設有一個Java類 TicketSearchForm:
import lombok.Data; @Data public class TicketSearchForm { private String status = "ALL"; }
在spring mvc Controller中,將該對象傳遞到Freemarker模板:
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"); // 設置狀態為OPEN model.addAttribute("previousSearch", previousSearch); return "ticket/search"; // 假設模板文件為 ticket/search.ftlh } }
對應的Freemarker模板 ticket/search.ftlh:
<option value="ALL" <#if previousSearch.status == "ALL">selected</#if>>Alle anzeigen</option> <option value="OPEN" selected#if>>Offen <option value="DONE" selected#if>>Geschlossen
在這個例子中,使用previousSearch.status == “ALL” 來比較字符串,可以正確地根據previousSearch對象的status屬性值來設置元素的默認選項。
注意事項
- 始終使用==運算符在Freemarker模板中比較字符串。
- 確保傳遞到Freemarker模板的對象屬性類型與模板中使用的類型一致。
- 在復雜的場景下,可以使用Freemarker提供的內置函數,如?string 將其他類型轉換為字符串后再進行比較。
總結
解決Freemarker模板引擎中NonHashException的關鍵在于理解Freemarker對字符串的處理方式。通過使用==運算符代替.equals()方法進行字符串比較,可以避免該錯誤的發生,并確保模板的正確執行。 記住,Freemarker的語法與Java有所不同,需要仔細區分。