在 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 属性绑定到 &lt;h:dataTable&gt;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>

错误提示 getKeygetValue 不存在。我可以理解这不是正确的方法。如何使用&lt;h:dataTable&gt; 呈现Map

【问题讨论】:

【参考方案1】:

在即将推出的 JSF 2.3 之前,UIData 组件(例如 &lt;h:dataTable&gt;&lt;p:dataTable&gt; 等)和 &lt;ui:repeat&gt;支持迭代 Map。这仅在 &lt;c:forEach&gt; 中受支持。

一种方法是将映射条目转换为数组(单独的 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>

另一种方法是将映射的条目集包装在&lt;h:dataTable&gt; 可以迭代的集合中,例如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&lt;User&gt;,其中User 类具有必要的属性idname

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 中忽略 JSF 输入 ID

如何正确使用带有 h:dataTable 的 ResultSet

如何在 <h:dataTable> 或 <ui:repeat> 中使用 <h:selectBooleanCheckbox> 来选择多个项目?

使用 include 和 h:datatable 进行递归 [重复]

h:commandButton 在 h:dataTable 中不起作用

使用带有Primefaces DynaForms的dataTable