【问题标题】:Freemarker iterating over hashmap keysFreemarker 迭代 hashmap 键
【发布时间】:2010-12-02 15:17:51
【问题描述】:

Freemarker 有两种集合数据类型,列表和哈希图 有没有办法像处理列表一样迭代 hashmap 键?

所以,如果我有一个带有数据的 var,可以说:

user : {
  name : "user"
  email : "looser@everything.com"
  homepage : "http://nosuchpage.org"
}

我想打印用户的所有属性及其值。 这是无效的,但目标很明确:

<#list user.props() as prop>
  ${prop} = ${user.get(prop)}
</#list>

【问题讨论】:

    标签: java freemarker


    【解决方案1】:

    编辑:不要将此解决方案与 FreeMarker 2.3.25 及更高版本一起使用,尤其是 .get(prop)。查看其他答案。

    您使用内置的keys 函数,例如这应该工作:

    <#list user?keys as prop>
        ${prop} = ${user.get(prop)}
    </#list>  
    

    【讨论】:

    • 语法在最新版本中有所不同,如我在答案中发布的链接所示。我知道这是一个老问题,但它在 Google 上排名很高。
    • 只是一个注释 - 您可以使用 ${user[prop]} 作为速记
    • 这是一个性能泄漏:对于每个键,它都需要检索值。遍历 entrySet() 没有这个问题。
    • 应该是 ${user[prop]}
    • 使用配置默认值user[prop] 的工作原理是propString(否则您目前需要user?api.get(prop)),但请注意,某些框架(我相信像Struts)使用一个现在已弃用的设置,其中方法名称与 Map 键混合,因此如果 props 的值恰好是 user Java 对象中的方法名称,那么您将获得方法而不是您的意思。这也是为什么在那些旧设置中他们总是使用user.get(prop)
    【解决方案2】:

    仅供参考,检索值的语法似乎已根据以下内容更改:

    http://freemarker.sourceforge.net/docs/ref_builtins_hash.html

    <#assign h = {"name":"mouse", "price":50}>
    <#assign keys = h?keys>
    <#list keys as key>${key} = ${h[key]}; </#list>
    

    【讨论】:

    • 这个语法有何不同?
    • 好答案 ;-) 请注意,在打印您的值时,您可能需要检查空值, ${key} = ${h[key ]}; #if>
    • 语法没有改变。 [key].get(key) 自古就存在。 .get(key) 对 FTL 没有什么特别之处,它只是调用公共 Java 方法。但只有在 FreeMarker 配置为公开 Map 方法时才能使用它。
    • 迭代时,我得到了方法(getClass、hashCode、equals、get、toString、class)......但是,我没有看到像“id”这样的任何属性,这就是我想得到一份清单。任何建议如何从该哈希中获取非方法属性列表?我需要知道这些属性名称。 :|
    【解决方案3】:

    从 2.3.25 开始,这样做:

    <#list user as propName, propValue>
      ${propName} = ${propValue}
    </#list>
    

    请注意,这也适用于非字符串键(与 map[key] 不同,当时必须写为 map?api.get(key))。

    2.3.25 之前的标准解决方案是:

    <#list user?keys as prop>
      ${prop} = ${user[prop]}
    </#list>
    

    然而,一些真正古老的 FreeMarker 集成使用了一种奇怪的配置,其中公共 Map 方法(如 getClass)显示为键。发生这种情况是因为他们使用的是纯BeansWrapper(而不是DefaultObjectWrapper),其simpleMapWrapper 属性保留在false 上。您应该避免这样的设置,因为它将方法与真正的 Map 条目混合在一起。但是如果你遇到这种不幸的设置,逃避这种情况的方法是使用暴露的Java方法,例如user.entrySet()user.get(key)等,而不是使用模板语言结构,例如?keysuser[key] .

    【讨论】:

    • 这非常有效。但是,我在 springsource IDE 中看到了错误。知道如何修复它吗?谢谢
    • @harshavmb 什么错误?它是否使用过时的 FreeMarker 插件,该插件带有旧的 FreeMarker 版本?
    • 不这么认为。已经从 jboss tools 下载了最新的一个。我会在其他机器上试一试,然后告诉你。
    • @harshavmb 如果您输入${x?nosuchthing} 之类的内容并将鼠标悬停在它上面,显示的错误消息将告诉您它使用的是哪个 FreeMarker 版本。应该是2.3.25-incubating
    • 奇怪,我刚在 Mac 上试过,无法复制问题。问题似乎只与我的虚拟机有关。我会看看jar版本。但是,这只是编辑器中的错误,但代码执行正确。
    【解决方案4】:

    如果使用暴露级别为 Expose.SAFE 或 Expose.ALL 的BeansWrapper,则可以采用迭代条目集的标准 Java 方法:

    例如,以下内容适用于 Freemarker(至少从 2.3.19 版开始):

    <#list map.entrySet() as entry>  
      <input type="hidden" name="${entry.key}" value="${entry.value}" />
    </#list>
    

    例如,在 Struts2 中,an extension of the BeanWrapper 与默认的曝光级别一起使用以允许这种迭代方式。

    【讨论】:

    • 你真的试过这个吗?因为我在尝试时得到了InvalidReferenceException,而map?keys 有效。
    • 这仅在使用 freemarker.ext.beans.BeansWrapper 作为对象包装器时有效。否则Maps 将自动包装到不支持#entrySet()SimpleHash 对象中。 (见freemarker.sourceforge.net/docs/api/freemarker/template/…
    • 你是对的,我已经更新了我的答案以反映你的评论。好看!
    • 如果您将 Spring Freemarker 解析器与 BeanWrapper 一起使用,则上述内容对于在 FTL 中创建的散列效果不佳。在 Ftl 文件中声明的散列没有被包装,仍然只是一个使用 ?keys 可迭代的散列。
    • 不要使用纯BeansWrapper,至少不要使用其默认值,其中simpleMapWrapperfalse。它变得非常混乱,因为它将键与方法名称混合在一起。如果您需要调用entrySet(),只需继续使用“干净”的对象包装器,就像默认的一样,如果您需要访问Java API 而不是键,请编写map?api.entrySet()
    【解决方案5】:

    迭代对象

    如果您的地图键是一个对象而不是字符串,您可以使用 Freemarker 对其进行迭代。

    1) 将地图转换为控制器中的列表:

    List<Map.Entry<myObjectKey, myObjectValue>> convertedMap  = new ArrayList(originalMap.entrySet());
    

    2)在Freemarker模板中迭代map,访问Key中的对象和Value中的对象:

    <#list convertedMap as item>
        <#assign myObjectKey = item.getKey()/>
        <#assign myObjectValue = item.getValue()/>
        [...]
    </#list>
    

    【讨论】:

      【解决方案6】:

      为了完整起见,值得一提的是,自最近以来,Freemarker 中的空集合处理得很好。

      所以迭代地图最方便的方法是:

      <#list tags>
      <ul class="posts">
          <#items as tagName, tagCount>
              <li>{$tagName} (${tagCount})</li>
          </#items>
      </ul>
      <#else>
          <p>No tags found.</p>
      </#list>
      

      不再有 &lt;#if ...&gt; 包装器。

      【讨论】:

      • 最佳答案。谢谢。
      【解决方案7】:

      您可以使用单引号来访问您在 Java 程序中设置的密钥。

      如果你像这样在 Java 中设置 Map

      Map<String,Object> hash = new HashMap<String,Object>();
      hash.put("firstname", "a");
      hash.put("lastname", "b");
      
      Map<String,Object> map = new HashMap<String,Object>();
      map.put("hash", hash);
      

      然后你可以像这样在 Freemarker 中访问 'hash' 的成员 -

      ${hash['firstname']}
      ${hash['lastname']}
      

      输出:

      a
      b
      

      【讨论】:

      • 显示如何处理单个键,但问题是如何迭代
      猜你喜欢
      • 1970-01-01
      • 2021-08-06
      • 2011-03-21
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多