FreeMarker Complex Collection

时间:2013-08-26 16:58:19

标签: spring struts2 freemarker

我有一个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中运行?

1 个答案:

答案 0 :(得分:2)

<强>更新

从2.3.22开始,有一个更容易和无中断的解决方案:配置FreeMarker以便?api工作,然后你可以使用Map的Java API,其中密钥不是' t String - s。有关详细信息,请参阅this FAQ entrythis 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相当有限,因此您不能在那里创建和配置(调用BeansWrapperFreeMarkerConfigurer。您当然可以在spring配置文件中执行此操作,但我没有找到将其注入freemarker.template.Configuration的方法,除非您将整个 FreeMarkerConfigurer对象创建为一个bean,并将其注入到具有configuration属性的BeansWrapper中。因此,最简单的解决方法可能是扩展simpleMapWrapper以覆盖默认的object_wrapper,然后通过object_wrapper引用该扩展类的类。 (以防万一有人稍后阅读,FreeMarker 2.3.21可能会扩展属性配置API,以便您可以将BeansWrapper() { simpleMapWrapper = true }设置为{{1}}。)