Freemarker iterating over hashmap keys

人盡茶涼 提交于 2019-11-26 20:10:40
skaffman

Edit: Don't use this solution with FreeMarker 2.3.25 and up, especially not .get(prop). See other answers.

You use the built-in keys function, e.g. this should work:

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

FYI, it looks like the syntax for retrieving the values has changed according to:

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>

Since 2.3.25, do it like this:

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

Note that this also works with non-string keys (unlike map[key], which had to be written as map?api.get(key) then).

Before 2.3.25 the standard solution was:

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

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. But if you run into such unfortunate setup, the way to escape the situation is using the exposed Java methods, such as user.entrySet(), user.get(key), etc., and not using the template language constructs like ?keys or user[key].

If using a BeansWrapper with an exposure level of Expose.SAFE or Expose.ALL, then the standard Java approach of iterating the entry set can be employed:

For example, the following will work in Freemarker (since at least version 2.3.19):

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

In Struts2, for instance, an extension of the BeanWrapper is used with the exposure level defaulted to allow this manner of iteration.

Iterating Objects

If your map keys is an object and not an string, you can iterate it using Freemarker.

1) Convert the map into a list in the controller:

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

2) Iterate the map in the Freemarker template, accessing to the object in the Key and the Object in the Value:

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

You can use a single quote to access the key that you set in your Java program.

If you set a Map in Java like this

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);

Then you can access the members of 'hash' in Freemarker like this -

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

Output :

a
b

For completeness, it's worth mentioning there's a decent handling of empty collections in Freemarker since recently.

So the most convenient way to iterate a map is:

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

No more <#if ...> wrappers.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!