在 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。
我有一个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。