Calcular soma total de todos os números em c: ciclo forEach
Pergunta
Eu tenho um bean Java como este:
class Person {
int age;
String name;
}
Eu gostaria de iterar sobre uma coleção de estes feijões em um JSP, mostrando cada pessoa em uma linha da tabela HTML, e na última linha da tabela Eu gostaria de mostrar o total de todas as idades.
O código para gerar as linhas da tabela será algo parecido com isto:
<c:forEach var="person" items="${personList}">
<tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
No entanto, eu estou lutando para encontrar uma maneira de calcular o total idade que será mostrado na linha final sem recorrer ao código scriptlet , alguma sugestão?
Solução
Nota: Eu tentei combinando respostas para fazer uma lista abrangente. Eu mencionei nomes quando necessário para dar crédito onde é devido.
Existem muitas maneiras de resolver este problema, com vantagens / desvantagens associadas a cada:
Pure JSP Solução
Como ScArcher2 mencionado acima, uma solução muito fácil e simples para o problema é para implementá-lo diretamente na JSP assim:
<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}
O problema com esta solução é que o JSP torna-se confuso para o ponto onde você poderia muito bem ter Scriplets introduzidas. Se você antecipar que todo mundo olhando para a página será capaz de seguir a lógica rudimentar presente é uma boa escolha.
solução EL Pure
Se você já está no EL 3.0 (Java EE 7 / Servlet 3.1), usar o novo suporte para córregos e 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()}
Funções JSP EL
Outra forma de saída do total sem introduzir código scriplet em sua JSP é usar uma função EL. funções EL permitem que você chamar um método estático público de uma classe pública. Por exemplo, se você gostaria de interagir sobre sua coleção e somar os valores que você pode definir um método estático público chamado sum (Lista de pessoas) em uma classe pública, talvez chamados PersonUtils. Em seu arquivo TLD você colocaria a seguinte declaração:
<function>
<name>sum</name>
<function-class>com.example.PersonUtils</function-class>
<function-signature>int sum(java.util.List people)</function-signature>
</function>
Dentro de sua JSP você escreveria:
<%@ taglib prefix="f" uri="/your-tld-uri"%>
...
<c:out value="${f:sum(personList)}"/>
JSP EL Funções ter alguns benefícios. Eles permitem que você use métodos Java existentes sem a necessidade de código para uma interface específica (Custom Tag Libraries). Eles também são compactos e não irá confundir a programação não-pessoa orientada.
Tag personalizado
No entanto, outra opção é para rolar a sua própria etiqueta personalizada. Esta opção irá envolver o mais configuração, mas vai dar o que eu acho que você está esentially procurando, absolutly não scriptlets. Um tutorial bom para usar marcas personalizadas simples podem ser encontradas em http : //java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701
As etapas envolvidas incluem subclasse 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;
}
}
Defina a marca em um arquivo 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>
Declare a taglib no topo de sua JSP:
<%@ taglib uri="/you-taglib-uri" prefix="p" %>
e utilize a tag:
<c:forEach var="person" items="${personList}">
<tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
<p:personSum personList="${personList}"/>
Exibição Tag
Como ZMF mencionado anteriormente, você também pode usar a tag de exibição, embora você terá que incluir as bibliotecas apropriadas:
Outras dicas
Você está tentando somar todas as idades?
Você poderia calculá-lo em seu controlador e só exibir o resultado no jsp.
Você pode escrever um tag personalizado para fazer o cálculo.
Você pode calcular-la no jsp utilizando JSTL assim.
<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}
Confira tag display. http://displaytag.sourceforge.net/11/tut_basic.html
ScArcher2 tem o mais simples solução . Se você queria algo mais compacto possível, você pode criar uma biblioteca de tag com uma função de "soma" nele. Algo como:
class MySum {
public double sum(List list) {...}
}
Em seu TLD:
<function>
<name>sum</name>
<function-class>my.MySum</function-class>
<function-signature>double sum(List)</function-signature>
</function>
Em seu JSP, você teria algo como:
<%@ taglib uri="/myfunc" prefix="f" %>
${f:sum(personList)}
É um pouco hacky, mas em seu código controlador você poderia simplesmente criar um objeto Pessoa manequim com o total nele!
Como você recuperar seus objetos? HTML permite definir um elemento que vai sentar-se na parte inferior de todos os dados você, portanto você poderia apenas definir o total de separadamente da Pessoa objetos e sua saída será na página tal como está, sem qualquer computação na página JSP.
Você pode iterar sobre uma coleção usando JSTL de acordo com a seguinte se é um mapa que você pode fazer no seguinte Calculando Totais / ou em outros resumos no controlador - não no JSP -. É realmente fortemente preferível Use o código de Java e uma abordagem MVC, por exemplo framework Spring MVC, em vez de tentar fazer muito em JSP ou JSTL; fazendo cálculo significativa nesses idiomas é fraco e lento, e faz suas páginas JSP muito menos claro. Exemplo: Design-decisão sábia -. Em qualquer lugar um total for necessário, pode conseguir próximo mês ser estendida para exigir uma média, a mediana, o desvio padrão cálculos JSTL e sumarização são pouco segurando juntos, em apenas recebendo um total. Você realmente vai querer cumprir quaisquer outras exigências sumárias no JSTL? Creio que a resposta é NÃO -. E que, portanto, a decisão de design correto é calcular no Controller, como igualmente / mais simples e definitivamente mais plausível-requisitos extensível <c:forEach items="${numList}" var="item">
${item}
</c:forEach>
<c:forEach items="${numMap}" var="entry">
${entry.key},${entry.value}<br/>
</c:forEach>
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);
}
}