在Facelets <ui:repeat>标签内使用<c:set>的EL变量

时间:2015-09-04 04:21:47

标签: jsf jstl el uirepeat

我有Home。每个Home都有一个Room列表。每个Room都有零个或多个Person s。

我想算一下每个家庭的总人数。但我无法在任何支持bean或实体中添加新变量来记录人数。因此,我只想通过<c:set>在视图中计算。

我的第一次尝试看起来像:

<c:set var="personCount" value="${0}" />
<ui:repeat var="home" value="#{mybackingBean.homes}">
    <ui:repeat var="room" value="#{home.rooms}">
        ${personCount += room.persons.size()}
    </ui:repeat>
    <h:panelGrid columns="2">
        <h:outputLabel value="#{home.id}" />
        <h:outputLabel value="#{personCount}" />
    </h:panelGrid>
</ui:repeat>

我怎样才能实现它?

1 个答案:

答案 0 :(得分:6)

有几个错误。

首先,

${personCount += room.persons.size()}

在EL中,+=string concatenation operator。所以,这基本上会给你String.valueOf(personCount) + String.valueOf(size)的结果。如果计数已初始化为0且有3个人,则会打印03

您基本上想要将personCount + size的结果重新分配回变量personCount。您需要使用<c:set>重新设置变量,如下所示。

<c:set var="personCount" value="${personCount + room.persons.size()}" />

第二,

<c:set var="personCount" value="${0}" />
<[for each home]>
    <[for each room]>
        <c:set var="personCount" value="${personCount + room.persons.size()}" />

personCount在两次迭代之外都使用0进行初始化。因此,对于每个家庭,您将以这种方式计算所有以前家庭的人。你想在第一次迭代中声明它。

<[for each home]>
    <c:set var="personCount" value="${0}" />
        <[for each room]>
            <c:set var="personCount" value="${personCount + room.persons.size()}" />

这与EL无关。这只是一个逻辑错误,它也会在“普通的”Java中引起同样的问题。

第三,

<c:set>之类的JSTL标记在视图构建期间运行(从XHTML模板转换为JSF组件树期间)。像<ui:repeat>这样的JSF组件在视图渲染时间(从JSF组件树转换为HTML输出期间)运行。因此,<c:set><ui:repeat>次迭代期间不会运行。因此,它无法看到迭代变量var。您基本上也需要在视图构建期间进行迭代。您可以使用JSTL <c:forEach>

所以,总而言之,您的意图解决方案如下:

<c:forEach items="#{bean.homes}" var="home">
    <c:set var="personCount" value="${0}" />
    <c:forEach items="#{home.rooms}" var="room">
        <c:set var="personCount" value="${personCount + room.persons.size()}" />
    </c:forEach>

    <h:panelGrid columns="2">
        <h:outputLabel value="#{home.id}" />
        <h:outputLabel value="#{personCount}" />
    </h:panelGrid>
</c:forEach>

有关深入解释,另请参阅JSTL in JSF2 Facelets... makes sense?

但是,由于+=运算符在您的情况下显然不会导致EL异常,这意味着您已经在使用EL 3.0。这反过来意味着您可以使用新的EL 3.0 lambda and stream features

<ui:repeat value="#{bean.homes}" var="home">
    <h:panelGrid columns="2">
        <h:outputLabel value="#{home.id}" />
        <h:outputLabel value="#{home.rooms.stream().map(room -> room.persons.size()).sum()}" />
    </h:panelGrid>
</ui:repeat>

不再需要计数循环了。不,这不需要Java 8,它在Java 7上运行良好。