Calculate total sum of all numbers in c:forEach loop

和自甴很熟 提交于 2019-12-17 03:03:54

问题


I have a Java bean like this:

class Person {
  int age;
  String name;
}

I'd like to iterate over a collection of these beans in a JSP, showing each person in a HTML table row, and in the last row of the table I'd like to show the total of all the ages.

The code to generate the table rows will look something like this:

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

However, I'm struggling to find a way to calculate the age total that will be shown in the final row without resorting to scriptlet code, any suggestions?


回答1:


Note: I tried combining answers to make a comprehensive list. I mentioned names where appropriate to give credit where it is due.

There are many ways to solve this problem, with pros/cons associated with each:

Pure JSP Solution

As ScArcher2 mentioned above, a very easy and simple solution to the problem is to implement it directly in the JSP as so:

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

The problem with this solution is that the JSP becomes confusing to the point where you might as well have introduced scriplets. If you anticipate that everyone looking at the page will be able to follow the rudimentary logic present it is a fine choice.

Pure EL solution

If you're already on EL 3.0 (Java EE 7 / Servlet 3.1), use new support for 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 Functions

Another way to output the total without introducing scriplet code into your JSP is to use an EL function. EL functions allow you to call a public static method in a public class. For example, if you would like to iterate over your collection and sum the values you could define a public static method called sum(List people) in a public class, perhaps called PersonUtils. In your tld file you would place the following declaration:

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

Within your JSP you would write:

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

JSP EL Functions have a few benefits. They allow you to use existing Java methods without the need to code to a specific UI (Custom Tag Libraries). They are also compact and will not confuse a non-programming oriented person.

Custom Tag

Yet another option is to roll your own custom tag. This option will involve the most setup but will give you what I think you are esentially looking for, absolutly no scriptlets. A nice tutorial for using simple custom tags can be found at http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701

The steps involved include subclassing 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;
   }
}

Define the tag in a tld file:

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

Declare the taglib on the top of your JSP:

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

and use the tag:

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

Display Tag

As zmf mentioned earlier, you could also use the display tag, although you will need to include the appropriate libraries:

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




回答2:


Are you trying to add up all the ages?

You could calculate it in your controller and only display the result in the jsp.

You can write a custom tag to do the calculation.

You can calculate it in the jsp using jstl like this.

<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:


Check out display tag. http://displaytag.sourceforge.net/11/tut_basic.html




回答4:


ScArcher2 has the simplest solution. If you wanted something as compact as possible, you could create a tag library with a "sum" function in it. Something like:

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

In your TLD:

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

In your JSP, you'd have something like:

<%@ taglib uri="/myfunc" prefix="f" %>

${f:sum(personList)}



回答5:


It's a bit hacky, but in your controller code you could just create a dummy Person object with the total in it!

How are you retrieving your objects? HTML lets you set a <TFOOT> element which will sit at the bottom of any data you have, therefore you could just set the total separately from the Person objects and output it on the page as-is without any computation on the JSP page.




回答6:


you can iterate over a collection using JSTL according to following

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

if it is a map you can do on the following

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



回答7:


Calculating Totals/ or other summaries in the controller -- not in the JSP -- is really strongly preferable.

Use Java code & an MVC approach, eg Spring MVC framework, instead of trying to do too much in JSP or JSTL; doing significant calculation in these languages is weak & slow, and makes your JSP pages much less clear.

Example:

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

Design decision-wise -- anywhere a total is required, could conceivably next month be extended to require an average, a median, a standard deviation.

JSTL calculations & summarization are scarcely holding together, in just getting a total. Are you really going to want to meet any further summary requirements in JSTL? I believe the answer is NO -- and that therefore the correct design decision is to calculate in the Controller, as equally/ more simple and definitely more plausible-requirements extensible.



来源:https://stackoverflow.com/questions/102964/calculate-total-sum-of-all-numbers-in-cforeach-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!