【问题标题】:Calculate total sum of all numbers in c:forEach loop计算 c:forEach 循环中所有数字的总和
【发布时间】:2023-04-03 21:28:01
【问题描述】:

我有一个这样的 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 代码,有什么建议吗?

【问题讨论】:

  • 您是否将所有年龄相加并在最后一行显示?

标签: jsp foreach sum jstl


【解决方案1】:

注意:我尝试将答案组合成一个综合列表。我在适当的地方提到了名字,以便在应得的地方给予赞扬。

解决这个问题的方法有很多,各有优缺点:

纯 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 变得混乱到您可能已经引入了 scriplet 的地步。如果您预计查看该页面的每个人都能够遵循呈现的基本逻辑,那么这是一个不错的选择。

纯 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(自定义标签库)。它们也很紧凑,不会让非编程导向的人感到困惑。

自定义标签

另一种选择是滚动您自己的自定义标签。这个选项将涉及最多的设置,但会给你我认为你正在寻找的东西,绝对没有脚本。可以在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

【讨论】:

  • 在控制器中计算总计——而不是在 JSP 中——确实是非常可取的。使用 MVC 框架,例如 Spring,而不是尝试在 JSP 或 JSTL 中做太多事情。
【解决方案2】:

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

你可以在你的控制器中计算它并且只在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}

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      ScArcher2 有最简单的solution。如果您想要尽可能紧凑的东西,您可以创建一个带有“sum”函数的标签库。比如:

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

      在您的顶级域名中:

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

      【讨论】:

      • 不是通用的——无法指定 sum() 用于计算的属性或函数结果。要么你已经走了很长的路来制作一个单一用途的运营商,要么你必须走得更远,通过反射来让它变得多才多艺。
      • 简短而正确的答案:在Controller中计算摘要,而不是在JSP中。
      【解决方案5】:

      这有点笨拙,但在您的控制器代码中,您可以创建一个包含总数的虚拟 Person 对象!

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

      【讨论】:

        【解决方案6】:

        您可以按照以下方式使用 JSTL 遍历集合

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

        如果是地图你可以在下面做

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

        【讨论】:

          【解决方案7】:

          在控制器中(而不是在 JSP 中)计算 Totals/ 或其他摘要确实非常可取。

          使用 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);
              }
          }
          

          明智的设计决策——任何需要总计的地方,下个月都可以扩展为需要平均值、中位数、标准差。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-12-16
            • 1970-01-01
            • 2020-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多