计算c:forEach循环中所有数字的总和

我有一个这样的Java bean:

class Person { int age; String name; } 

我想在JSP中迭代这些bean的集合,在HTML表格行中显示每个人,在表格的最后一行中,我想显示所有年龄段的总数。

生成表格行的代码如下所示:

 <c:forEach var="person" items="${personList}"> <tr><td>${person.name}<td><td>${person.age}</td></tr> </c:forEach> 

但是,我正在努力寻找一种方法来计算将在最后一行中显示的年龄总和, 而不诉诸scriptlet代码 ,有什么build议?

注意:我尝试将答案合并为一个全面的列表。 我在适当的地方提到名称,以便在哪里提供信用。

有很多方法可以解决这个问题,每个方面都有优点/缺点:

纯JSP解决scheme

正如上面提到的ScArcher2一样,解决这个问题的一个非常简单的方法就是直接在JSP中实现,如下所示:

 <c:set var="ageTotal" value="${0}" /> <c:forEach var="person" items="${personList}"> <c:set var="ageTotal" value="${ageTotal + person.age}" /> <tr><td>${person.name}<td><td>${person.age}</td></tr> </c:forEach> ${ageTotal} 

这个解决scheme的问题是JSP变得混乱,以至于你可能已经引入了脚本。 如果您预期每个看到该页面的人都能够遵循目前的基本逻辑,那么这是一个不错的select。

纯EL解决scheme

如果您已经使用EL 3.0(Java EE 7 / Servlet 3.1),请使用对stream和lambdas的新支持:

 <c:forEach var="person" items="${personList}"> <tr><td>${person.name}<td><td>${person.age}</td></tr> </c:forEach> ${personList.stream().map(person -> person.age).sum()} 

JSP EL函数

输出总量而不将脚本代码引入JSP的另一种方法是使用EL函数。 EL函数允许您在公共类中调用公共静态方法。 例如,如果您想迭代您的集合并对这些值进行求和,则可以在公共类(可能称为PersonUtils)中定义一个名为sum(List people)的公共静态方法。 在你的tld文件中,你可以放置下面的声明:

 <function> <name>sum</name> <function-class>com.example.PersonUtils</function-class> <function-signature>int sum(java.util.List people)</function-signature> </function> 

在你的JSP中,你会写:

 <%@ taglib prefix="f" uri="/your-tld-uri"%> ... <c:out value="${f:sum(personList)}"/> 

JSP EL函数有几个好处。 它们允许您使用现有的Java方法,而无需编写特定的UI(自定义标签库)。 它们也很紧凑,不会混淆非编程导向的人。

自定义标签

还有一个select是推出自己的自定义标签。 这个选项将涉及最多的设置,但会给你我觉得你实际上寻找,绝对没有scriptlet。 使用简单的自定义标签的一个很好的教程可以在http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701find

涉及的步骤包括子类别TagSupport:

 public PersonSumTag extends TagSupport { private List personList; public List getPersonList(){ return personList; } public void setPersonList(List personList){ this.personList = personList; } public int doStartTag() throws JspException { try { int sum = 0; for(Iterator it = personList.iterator(); it.hasNext()){ Person p = (Person)it.next(); sum+=p.getAge(); } pageContext.getOut().print(""+sum); } catch (Exception ex) { throw new JspTagException("SimpleTag: " + ex.getMessage()); } return SKIP_BODY; } public int doEndTag() { return EVAL_PAGE; } } 

在tld文件中定义标签:

 <tag> <name>personSum</name> <tag-class>example.PersonSumTag</tag-class> <body-content>empty</body-content> ... <attribute> <name>personList</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.util.List</type> </attribute> ... </tag> 

在JSP的顶部声明taglib:

 <%@ taglib uri="/you-taglib-uri" prefix="p" %> 

并使用标签:

 <c:forEach var="person" items="${personList}"> <tr><td>${person.name}<td><td>${person.age}</td></tr> </c:forEach> <p:personSum personList="${personList}"/> 

显示标签

正如前面提到的zmf,你也可以使用display标签,尽pipe你需要包含相应的库:

http://displaytag.sourceforge.net/11/tut_basic.html

你想把所有年龄加起来吗?

你可以在你的控制器中计算它,只显示结果在jsp中。

您可以编写自定义标签来进行计算。

你可以用jstl这样在jsp中计算它。

 <c:set var="ageTotal" value="${0}" /> <c:forEach var="person" items="${personList}"> <c:set var="ageTotal" value="${ageTotal + person.age}" /> <tr><td>${person.name}<td><td>${person.age}</td></tr> </c:forEach> ${ageTotal} 

ScArcher2有最简单的解决scheme 。 如果你想要尽可能紧凑的东西,你可以创build一个带有“和”function的标签库。 就像是:

 class MySum { public double sum(List list) {...} } 

在您的TLD中:

 <function> <name>sum</name> <function-class>my.MySum</function-class> <function-signature>double sum(List)</function-signature> </function> 

在你的JSP中,你会有这样的东西:

 <%@ taglib uri="/myfunc" prefix="f" %> ${f:sum(personList)} 

这有点不好意思,但是在你的控制器代码中,你可以创build一个虚拟的Person对象。

你如何检索你的对象? 通过HTML,您可以设置一个<TFOOT>元素,它将位于您拥有的任何数据的底部,因此您可以从Person对象中单独设置总数,并在页面上将其原样输出,而无需在JSP页面上进行任何计算。

您可以按照以下步骤使用JSTL迭代集合

 <c:forEach items="${numList}" var="item"> ${item} </c:forEach> 

如果这是一个地图,你可以在下面做

 <c:forEach items="${numMap}" var="entry"> ${entry.key},${entry.value}<br/> </c:forEach> 

在控制器中计算汇总/或其他汇总 – 不在JSP中 – 是非常可取的。

使用Java代码和一个MVC方法,例如Spring MVC框架,而不是试图在JSP或JSTL中做太多; 在这些语言中进行重要的计算是微弱和缓慢的,并且使得您的JSP页面不太清晰。

例:

 class PersonList_Controller implements Controller { ... protected void renderModel (List<Person> items, Map model) { int totalAge = 0; for (Person person : items) { totalAge += person.getAge(); } model.put("items", items); model.put("totalAge", totalAge); } } 

devise决策方面 – 任何地方都需要,下个月可能会延长到要求平均值,中位数,标准偏差。

JSTL的计算和总结几乎没有在一起,只是总得来的。 你真的想要满足JSTL的任何进一步的总结要求吗? 我相信答案是否定的 – 因此,正确的devise决策是在控制器中进行计算,因为同样/更简单,更合理的要求是可扩展的。