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

时间:2008-09-19 15:35:43

标签: jsp foreach sum jstl totals

我有一个像这样的Java bean:

class Person {
  int age;
  String name;
}

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

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

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

但是,我很难找到一种方法来计算将在最后一行显示的年龄总计而不诉诸于scriptlet代码,是否有任何建议?

7 个答案:

答案 0 :(得分:38)

注意: 我尝试将答案组合成一个全面的列表。我提到了适当的名称,以便在到期时提供信用。

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

纯JSP解决方案

正如上面提到的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}

这个解决方案的问题在于JSP变得令人困惑,你可能已经引入了scriplets。如果您预计每个看页面的人都能够遵循现有的基本逻辑,那么这是一个不错的选择。

纯EL解决方案

如果您已经使用EL 3.0(Java EE 7 / Servlet 3.1),请使用streams and 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功能

在不将scriplet代码引入JSP的情况下输出总数的另一种方法是使用EL函数。 EL函数允许您在公共类中调用公共静态方法。例如,如果您想迭代集合并对值求和,则可以在公共类中定义名为sum(List people)的公共静态方法,可能称为PersonUtils。在您的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(自定义标记库)。它们也很紧凑,不会混淆非编程人员。

自定义标记

另一种选择是推送自己的自定义标签。这个选项将涉及最多的设置,但会给你我认为你真正寻找的东西,绝对没有scriptlets。可以在http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701

找到使用简单自定义标记的精彩教程

所涉及的步骤包括继承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标签,尽管你需要包含相应的库:

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

答案 1 :(得分:4)

你是否想要累积所有年龄?

您可以在控制器中计算它,只在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}

答案 2 :(得分:3)

答案 3 :(得分:1)

ScArcher2拥有最简单的solution。如果你想要一些尽可能紧凑的东西,你可以创建一个带有“sum”功能的标签库。类似的东西:

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)}

答案 4 :(得分:0)

有点hacky,但是在你的控制器代码中,你可以创建一个带有总数的虚拟Person对象!

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

答案 5 :(得分:0)

您可以根据以下

使用JSTL迭代集合
<c:forEach items="${numList}" var="item">
      ${item}
</c:forEach>

如果是地图,您可以执行以下操作

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

答案 6 :(得分:0)

计算控制器中的总计/或其他摘要 - 而不是在JSP中 - 是非常可取的。

使用Java代码&amp;一种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);
    }
}

设计决策 - 在需要总计的任何地方,可以想象下个月可以扩展到需要平均值,中位数,标准偏差。

JSTL计算&amp;总结几乎没有结合在一起,总而言之。您真的想要在JSTL中满足任何进一步的摘要要求吗?我认为答案是否定的 - 因此正确的设计决策是在控制器中进行计算,同样/更简单,更明确的更合理的要求是可扩展的。