一個問題引發的思考 來看場景 1 我有一個 java 的 Map 變量, 希望在 ftl 檔案中被 list 循環疊代顯示到頁面, 示例如下 java代碼片段 1 Map<String, String> javaMap = new HashMap<String, String>(); javaMap.put(“a”, “A”); javaMap.put(“b”, “B”); ftl代碼片段 1 <#list javaMap.keySet() as ke> <p>${ke}=${javaMap[ke]}</p> </#list> 渲染出的ftl代碼 <p>a=A</p> <p>b=B</p> ftl代碼片段 2 <#list javaMap?keys as ke> <p>${ke}=${javaMap[ke]}</p> </#list> 渲染出的ftl代碼 模闆渲染錯誤, 在${javaMap[ke]}地方渲染發生錯誤 ftl代碼片段 3 <#list javaMap?keys as ke> ${ke}; </#list> 渲染出的ftl代碼 hashCode;keyOne;getClass;get;values;toString;keyTwo;clone;keySet;containsValue;notifyAll;clear;size;empty;entrySet;isEmpty;class;put;putAll;remove;containsKey;equals;wait;notify; 在看場景 2 java代碼片段 2 String javaString = “{'a':'A','b':'B'}”; ftl代碼片段 4 <#assign ftlBeanObj = javaString?eval> 驗證 , 對象會是Map特性的對象嗎 <#list ftlBeanObj.keySet() as ke> <p>${ke}=${ftlBeanObj[ke]}</p> </#list> 驗證 -結果如下,渲染出的html代碼 模闆渲染錯誤, 在 ftlBeanObj.keySet() 地方渲染發生錯誤, 沒找到這個方法 ftl代碼片段 5 <#assign ftlBeanObj = javaString?eval> 驗證 , 對象會是JSON特性的對象嗎 <#list ftlBeanObj?keys as ke> <p>${ke}=${ftlBeanObj[ke]}</p> </#list> 驗證 -結果如下,渲染出的html代碼 <p>a=A</p> <p>b=B</p> 分析, 在前文環境中 javaMap是一個java的對象, 若想正确的周遊其記憶體儲的鍵值對, 需要使用對象自身方法 Map.keySet() 方法來周遊 若使用ftl專屬文法 ?keys, 将會把 javaMap 對象這個HashMap類自身的java.method當作對象的屬性, 在這裡被周遊出來 javaString?eval 這個ftl專屬文法将建構一個ftl專屬的 DefaultObjectWrapper 對象, 此時需要使用 ?keys 文法,才能正确的周遊出其内部的實際鍵值對 這裡建構出來的對象不具有Map性質
思考 有文章提到 javaMap 的這種周遊現象是因為 ftl 将 java Object 轉為 BeansWrapper 對象了, 而不是轉為 DefaultObjectWrapper 對象 原文如下 However, some really old FreeMarker integrations use a strange configuration, where the public Map methods (like getClass) appear as keys. That happens as they are using a pure BeansWrapper (instead of DefaultObjectWrapper) whose simpleMapWrapper property was left on false. You should avoid such a setup, as it mixes the methods with real Map entries. 要想使用 javaMap.keySet() 方式周遊鍵值對, 需要調整 ftl 的初始配置(ps: 本人還未嘗試,不确定配置改動是否能正常得到後文提到的結果 在配置檔案中加入如下配置: <prop key="object_wrapper">freemarker.ext.beans.BeansWrapper</prop> 在 OFBiz 中這個配置的初始化如下, 這裡是 BeansWrapper 對象 // import freemarker.ext.beans. BeansWrapper; // import freemarker.ext.beans. BeansWrapperBuilder; // import freemarker. template. Configuration; // import freemarker. template. Version; Version version = Configuration. VERSION_2_3_24; Configuration newConfig = new Configuration(version); BeansWrapper wrapper = new BeansWrapperBuilder(version).build(); newConfig.setObjectWrapper(wrapper); 若如 OFBiz 中這種配置, 确實會如前文 javaMap.keySet() 周遊正常; javaMap?keys 周遊出錯; <!--?xml version="1.0" encoding="UTF-8" standalone="no"?--> 在 Moqui 中這個配置的初始化如下, 這裡是 BeansWrapper 對象 [org.moqui.impl.context.renderer.FtlTemplateRenderer#makeFtlConfiguration] // Version FTL_VERSION = Configuration.VERSION_2_3_25; Configuration newConfig = new MoquiConfiguration ( FTL_VERSION, ecfi ); BeansWrapper defaultWrapper = new BeansWrapperBuilder ( FTL_VERSION ). build (); newConfig. setObjectWrapper (defaultWrapper ); 若如 Moqui 中這種配置, 也會如前文 javaMap.keySet() 周遊正常; javaMap?keys 周遊出錯; 參考連結 [ https://www.eertime.com/archives/255.html]
<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->
[ https://stackoverflow.com/questions/1497777/freemarker-iterating-over-hashmap-keys]