在 h:dataTable 中使用 java.util.Map
Posted
技术标签:
【中文标题】在 h:dataTable 中使用 java.util.Map【英文标题】:Using java.util.Map in h:dataTable 【发布时间】:2012-12-29 21:48:47 【问题描述】:我需要使用<h:dataTable>
显示Map
。我的支持 bean 有一个 Map
属性,如下所示:
public class Bean
private Map<Integer,String> map; // +getter
@PostConstruct
public void init()
map = new TreeMap<Integer,String>();
map.put(1,"Sasi");
map.put(2,"Pushparaju");
map.put(3,"Venkat Raman");
map.put(3,"Prabhakaran");
然后在 JSF 页面中,我尝试将此 Map
属性绑定到 <h:dataTable>
的 value
属性。
<h:dataTable border="1" value="#bean.map" var="map">
<h:column id="column1">
<f:facet name="header">
<h:outputText value="UserId"></h:outputText>
</f:facet>
<h:outputText value="#map.getKey"></h:outputText>
</h:column>
<h:column id="column2">
<f:facet name="header">
<h:outputText value="Email Id"></h:outputText>
</f:facet>
<h:outputText value="#map.getValue"></h:outputText>
</h:column>
</h:dataTable>
错误提示 getKey
和 getValue
不存在。我可以理解这不是正确的方法。如何使用<h:dataTable>
呈现Map
?
【问题讨论】:
【参考方案1】:在即将推出的 JSF 2.3 之前,UIData
组件(例如 <h:dataTable>
、<p:dataTable>
等)和 <ui:repeat>
不支持迭代 Map
。这仅在 <c:forEach>
中受支持。
一种方法是将映射条目转换为数组(单独的 entrySet()
将不起作用,因为 UIData
也不支持 Set
,直到即将推出的 JSF 2.3)。
<h:dataTable value="#bean.map.entrySet().toArray()" var="entry">
<h:column>#entry.key</h:column>
<h:column>#entry.value</h:column>
</h:dataTable>
另一种方法是将映射的条目集包装在<h:dataTable>
可以迭代的集合中,例如ArrayList
。
public class Bean
private Map<Integer, String> map;
private List<Entry<Integer, String>> entries; // +getter (no setter necessary)
@PostConstruct
public void init()
map = new TreeMap<>();
map.put(1, "Sasi");
map.put(2, "Pushparaju");
map.put(3, "Venkat Raman");
map.put(4, "Prabhakaran");
entries = new ArrayList<>(map.entrySet());
// ...
<h:dataTable value="#bean.entries" var="entry">
<h:column>#entry.key</h:column>
<h:column>#entry.value</h:column>
</h:dataTable>
然而,更简洁、自我记录和可重用的是使用List<User>
,其中User
类具有必要的属性id
和name
。
public class Bean
private List<User> users; // +getter (no setter necessary)
@PostConstruct
public void init()
users = new ArrayList<>();
users.add(new User(1, "Sasi"));
users.add(new User(2, "Pushparaju"));
users.add(new User(3, "Venkat Raman"));
users.add(new User(4, "Prabhakaran"));
// ...
<h:dataTable value="#bean.users" var="user">
<h:column>#user.id</h:column>
<h:column>#user.name</h:column>
</h:dataTable>
【讨论】:
嗨 BalusC..,Entry
是非 Serializable
接口。使用ViewScoped
Bean 时不影响。 [p.s 我正在使用LinkedHashMap
]?
@KishorP:不。对于未来不相关的问题和/或更详细的答案,请按“”按钮。【参考方案2】:
你也可以试试这个替代方案。
<h:dataTable border="1" value="#myBean.map.keySet().toArray()" var="myVar">
<h:column id="column1">
<f:facet name="header">
<h:outputText value="UserId"></h:outputText>
</f:facet>
<h:outputText value="#myVar"></h:outputText>
</h:column>
<h:column id="column2">
<f:facet name="header">
<h:outputText value="Email Id"></h:outputText>
</f:facet>
<h:outputText value="#myBean.map.get(myVar)"></h:outputText>
</h:column>
</h:dataTable>
【讨论】:
这是非常低效的性能。value
属性中的 EL 表达式在每个迭代轮次中进行评估。因此,在每一轮迭代中都会读取映射键集并将其转换为数组。而且,map.get(key)
不必要地在地图上进行第二次迭代以获得值。因此,您在每次迭代期间执行的迭代中有一个嵌套迭代!您至少应该改用map.entrySet()
,并且最好将其包装在一个固定的数组列表中。与当前接受的答案完全相同。【参考方案3】:
关于 prageeth 的最后一个答案,您可以使用 entrySet 而不是 keySet;那么你就可以摆脱 myBean.map.get 了。看这个例子:
<h:dataTable border="1" value="#myBean.map.entrySet().toArray()" var="map">
<h:column id="column1">
<f:facet name="header">
<h:outputText value="UserId"></h:outputText>
</f:facet>
<h:outputText value="#map.key"></h:outputText>
</h:column>
<h:column id="column2">
<f:facet name="header">
<h:outputText value="Email Id"></h:outputText>
</f:facet>
<h:outputText value="#map.value"></h:outputText>
</h:column>
</h:dataTable>
这适用于 myfaces 2.2.3,因为我自己刚刚使用过。
注:我最好把上个帖子评论一下,但我的声誉不够高,所以这是一个额外的答案。
【讨论】:
以上是关于在 h:dataTable 中使用 java.util.Map的主要内容,如果未能解决你的问题,请参考以下文章
如何正确使用带有 h:dataTable 的 ResultSet
如何在 <h:dataTable> 或 <ui:repeat> 中使用 <h:selectBooleanCheckbox> 来选择多个项目?
使用 include 和 h:datatable 进行递归 [重复]