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

Cat*_*ysm 5 jsf jstl el uirepeat

我有一个Home.每个Home都有一个Rooms 列表.每个Room都有零个或多个Persons.

我想算一下每个家庭的总人数.但我无法添加新变量来记录任何支持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>
Run Code Online (Sandbox Code Playgroud)

我怎样才能实现它?

Bal*_*usC 6

有几个错误.


第一,

${personCount += room.persons.size()}
Run Code Online (Sandbox Code Playgroud)

在EL中,+=字符串连接运算符.所以,这基本上会给你带来的结果String.valueOf(personCount) + String.valueOf(size).如果计数被初始化为0并且有人3,则将打印03.

您基本上想要将结果重新分配personCount + size给变量personCount.您需要使用<c:set>如下重新设置变量.

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

第二,

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

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

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

这与EL无关.这只是一个逻辑错误,它也会在"普通的"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="${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>
Run Code Online (Sandbox Code Playgroud)

有关深入解释,请参阅JSF2 Facelets中的JSTL ......有意义吗?


但是,由于+=操作员在您的情况下显然不会导致EL异常,这意味着您已经在使用EL 3.0.这反过来意味着您可以使用新的EL 3.0 lambda和流功能.

<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>
Run Code Online (Sandbox Code Playgroud)

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