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

Using EL variable of <c:set> inside Facelets <ui:repeat> tags

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

我想统计每个家庭的总人数。但我无法添加新变量来记录任何支持 bean 或实体中的人数。所以我只想通过 <c:set>.

在视图中计算它

我的第一次尝试是这样的:

<c:set var="personCount" value="[=12=]" />
<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>

如何实现?

有几个错误。


首先,

${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="[=12=]" />
<[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="[=13=]" />
        <[for each room]>
            <c:set var="personCount" value="${personCount + room.persons.size()}" />

这与 EL 无关。这只是一个逻辑错误,也会在 "plain vanilla" Java 中导致同样的问题。


第三,

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

所以,总而言之,您的预期解决方案如下所示:

<c:forEach items="#{bean.homes}" var="home">
    <c:set var="personCount" value="[=14=]" />
    <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。