1

我有一个 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 中工作?

4

1 回答 1

2

更新:

从 2.3.22 开始,有一个更简单且无中断的解决方案:配置 FreeMarker 以使其?api工作,然后您可以使用Map密钥不是String-s 的 Java API。有关更多详细信息,请参阅此常见问题解答条目此答案

现在强烈反对使用 Strut 的 FreeMarker 设置。当然,在那时,当他们这样做时,这可能是最合理的解决方法,但它不再是一段时间了,尤其是从 2.3.22 开始。

旧答案(过时):

您从模板中查看 Java 对象的方式取决于所ObjectWrapper使用的,这是一个 FreeMarker 配置设置。根据您的示例,Struts 使用 aBeansWrapper及其默认设置,而 Spring 可能使用DefaultObjectWrapper. 所以这导致了差异。我不建议使用任何一种,因为:

  • 使用BeansWrapper其默认设置Map键与方法名称混合,方法名称具有优先权。当然,您可以安全地使用myMap.get(key)它来解决这个问题,但myMap.get('foo')与 相比myMap.foo,这太可怕了,它只会在您没有调用方法的情况下起作用foo。也?keys将返回真正的键和方法名称的混合......这是一团糟。

  • 有了DefaultObjectWrapper您可以安全地编写myMap.foo,但您将无法获取具有非字符串键的实体,因为myMap[key]仅支持字符串,而您不再拥有myMag.get(key)

所以我通常与 FreeMarker 一起使用的是bw = new BeansWrapper(); bw.setSimpleMapWrapper(true). 有了这个,Map-s 的方法是不可见的,就像 with 一样DefaultObjectWrapper,所以你可以安全myMap.foo地使用myMap[key]。但是,如果您很少需要使用非字符串键获取某些内容,则可以使用myMap(nonStringKey)(是的,使用()而不是[])。最后一个不适用于DefaultObjectWrapper. (希望 FreeMarker 2.4 能解决这个乱七八糟的非字符串键问题,但它不会很快出现......)

那么接下来的问题是如何用Spring设置对象包装器。我不在家。据我所知,您有一个具有属性的FreeMarkerConfigurerbean,该属性是最终传递给基于 FreeMarker 的配置 API 的对象。因此,您应该能够添加一个引用要使用的类名的属性(或者它可能只是像 Struts 那样使用默认实例)。问题是,基于属性的 API 相当有限,因此您不能同时创建和配置(调用) a 。您当然可以在 spring 配置文件中执行此操作,但我看不到将其注入 的方法,除非您创建整个freemarkerSettingsPropertiesPropertiesobject_wrapperObjectWrapperbeansBeansWrappersetSimpleMapWrapperBeansWrapperFreeMarkerConfigurer freemarker.template.Configuration对象作为 bean,并将其注入到它FreeMarkerConfigurerconfiguration属性中。因此,也许最简单的解决方法是扩展BeansWrapper以覆盖 的默认值simpleMapWrapper,然后通过object_wrapper. (以防有人稍后阅读,FreeMarker 2.3.21 可能会扩展属性配置 API,以便您可以设置object_wrapperBeansWrapper() { simpleMapWrapper = true }。)

于 2013-08-28T15:05:16.297 回答