我有一个HashMap为Map<Long, List<Map<String, Object>>> typeAndKno
,在FreeMarker页面中,我得到了这张地图的内容:
<#list typeAndKno?keys as typeId>
${typeAndKno.get(typeId).get(0).get('TYPE_NAME')}
<#list typeAndKno.get(typeId) as kno>
${kno.get('KNOWLEDGE_ID')}
</#list>
</#list>
此代码在Struts2中运行良好,但在转移到Spring MVC后,代码失败。我终于将代码更改为:
<#list typeAndKno?keys as typeId>
${typeAndKno[typeId]?first['TYPE_NAME']}
<#list typeAndKno[typeId?string] as kno>
${kno['KNOWLEDGE_ID']}
</#list>
</#list>
这两段代码有什么区别?有没有办法让第一段代码在Spring MVC中运行?
答案 0 :(得分:2)
<强>更新强>
从2.3.22开始,有一个更容易和无中断的解决方案:配置FreeMarker以便?api
工作,然后你可以使用Map
的Java API,其中密钥不是' t String
- s。有关详细信息,请参阅this FAQ entry或this answer。
Strut的FreeMarker设置现在非常令人沮丧。当然,那时候,当他们这样做时,这可能是最合理的解决方法,但暂时不再存在,特别是从2.3.22开始。
旧答案(过时):
您从模板中看到Java对象的方式取决于所使用的ObjectWrapper
,这是一个FreeMarker配置设置。根据您的示例,Struts使用BeansWrapper
及其默认设置,而Spring可能使用DefaultObjectWrapper
。所以这会导致差异。我不建议使用其中之一,因为:
BeansWrapper
及其默认设置Map
键与方法名称混合,方法名称具有优先级。当然,您可以安全地使用myMap.get(key)
来解决这个问题,但与myMap.get('foo')
相比,myMap.foo
只是可怕的,只有在您没有名为foo
的方法时才能使用?keys
。另外DefaultObjectWrapper
将返回真实密钥和方法名称的混合...它是一团糟。
使用myMap.foo
,您可以安全地编写myMap[key]
,但是您将无法获取具有非字符串键的实体,因为myMag.get(key)
仅支持字符串,而您没有bw = new BeansWrapper(); bw.setSimpleMapWrapper(true)
了。
所以我通常与FreeMarker一起使用的是Map
。有了这个,DefaultObjectWrapper
- s的方法就不可见,就像使用myMap.foo
一样,因此您可以安全地使用myMap[key]
和myMap(nonStringKey)
。但是,如果您很少需要使用非字符串键获取内容,则可以使用()
(是的,使用[]
代替DefaultObjectWrapper
)。最后一个不适用于FreeMarkerConfigurer
。 (希望FreeMarker 2.4可以用非字符串密钥来解决这个问题,但它不会很快就会出来......)
接下来的问题是如何使用Spring设置对象包装器。我不在家。据我所知,你有一个freemarkerSettings
bean,它有一个Properties
属性,它是一个Properties
对象,最终传递给FreeMarker基于object_wrapper
的配置API。因此,您应该能够添加一个ObjectWrapper
属性,该属性引用要使用的beans
的类名(或者它可能只是BeansWrapper
来使用默认的setSimpleMapWrapper
实例像Struts那样)。问题是,基于属性的API相当有限,因此您不能在那里创建和配置(调用BeansWrapper
)FreeMarkerConfigurer
。您当然可以在spring配置文件中执行此操作,但我没有找到将其注入freemarker.template.Configuration
的方法,除非您将整个 FreeMarkerConfigurer
对象创建为一个bean,并将其注入到具有configuration
属性的BeansWrapper
中。因此,最简单的解决方法可能是扩展simpleMapWrapper
以覆盖默认的object_wrapper
,然后通过object_wrapper
引用该扩展类的类。 (以防万一有人稍后阅读,FreeMarker 2.3.21可能会扩展属性配置API,以便您可以将BeansWrapper() { simpleMapWrapper = true }
设置为{{1}}。)