jsp - index - jstl foreach items
javax.servlet.ServletException: javax.servlet.jsp.JspTagException: No sé cómo iterar sobre los "elementos" provistos en<forEach> (2)
Debería poder iterar sobre los encabezados
<tr>
<c:foreach var="heading" items="${results.headings}">
<th>${heading}</th>
</c:foreach>
</tr>
Y luego sobre los datos ...
<c:foreach var="row" items="${results.data}">
<tr>
<c:foreach var="i" items="${row}">
<td>${i}</td>
</c:foreach>
</tr>
</c:foreach>
¿O algo por el estilo?
Tengo un Bean que contiene los resultados. Necesito usar JSTL para iterar sobre él y presentar los resultados. Aquí está el frijol:
public class DetResults
{
private List<String> headings;
private List<Class<?>> types;
private List<Object[]> data;
public DetResults() {}
public List<String> getHeadings() { return this.headings; }
public String getHeading(int which) { return this.headings.get(which); }
public List<Class<?>> getTypes() { return this.types; }
public Class<?> getType(int which) { return this.types.get(which); }
public List<Object[]> getData( ) { return this.data; }
public Object[] getDataAtRow( int row ) { return this.data.get(row); }
public void setHeadings( List<String> val ) { this.headings = val; }
public void setHeadings( String[] val ) { this.headings = Arrays.asList(val); }
public void addHeading( String val )
{
if( this.headings == null ) this.headings = new ArrayList<String>();
this.headings.add(val);
}
public void setTypes( List<Class<?>> val ) { this.types = val; }
public void setTypes( Class<?> val[] ) { this.types = Arrays.asList(val); }
public void addType( Class<?> val )
{
if( this.types == null ) this.types = new ArrayList<Class<?>>();
this.types.add(val);
}
public void setData( List<Object[]> val ) { this.data = val; }
// allow NPE to get thrown
public void setDataAtRow( Object[] val, int row ) { this.data.set(row, val); }
public void appendDataRow( Object[] val )
{
if( data == null ) data = new ArrayList<Object[]>();
this.data.add(val);
}
public int getColumnCount() { return this.headings!=null?this.headings.size():0; }
}
Aquí está el controlador que establecerá el bean en JSP:
DetResults results = detDAO.fetchDetResults(paramBean);
request.setAttribute("results", results);
action.setJspURI(".../.jsp");
Traté de mostrarlo de la siguiente manera:
<c:forEach var="results" items="${results}">
${results.heading}
</c:forEach>
Pero arrojó la siguiente excepción:
Causado por: javax.servlet.ServletException: javax.servlet.jsp.JspTagException: No sé cómo iterar sobre los "elementos" provistos en <forEach>
Si registro los resultados en la página de mi controlador de esta manera:
System.out.println( "/n/nthere are " + results.getColumnCount() + " columns in the result set" );
for( int i=0; i<results.getColumnCount(); i++ )
{
System.out.println( results.getHeading(i) + " --> " + results.getType(i) );
}
El registro parece mostrar bien en el servidor.
Causado por: javax.servlet.ServletException: javax.servlet.jsp.JspTagException: No sé cómo iterar sobre los "elementos" provistos en
<forEach>
Eso sucederá cuando el <c:forEach items>
no refiera un objeto válido sobre el cual pueda iterar. El objeto debe ser un Object[]
(una matriz simple), una Collection
, Map
, Iterator
, Enumeration
o String
(ver también el código fuente ). Cualquier cosa más no puede ser iterada por <c:forEach>
. Su clase DetResults
no es una instancia de ninguno de los tipos mencionados anteriormente, por lo que fallará.
Su clase DetResults
no se ve bien. Se ve básicamente como un grano de Dios con una colección de todas las propiedades de múltiples entidades individuales. Esto no está bien. Una clase de bean debe representar como máximo una entidad. Reescribe tu clase DetResults
para que básicamente termines con una colección completa de JavaBeans:
List<DetResult> results = detDAO.fetchDetResults(paramBean);
para que pueda acceder a él de la siguiente manera:
<c:forEach items="${results}" var="result">
${result.heading}
<c:forEach items="${result.data}" var="dataItem">
${dataItem}
</c:forEach>
</c:forEach>
Si realmente insistes en mantener tu bean DetResults
tal como está, puedes acceder a él de la siguiente manera:
<c:forEach begin="0" end="${results.columnCount}" varStatus="loop">
${results.headings[loop.index]}
<c:forEach items="${results.data[loop.index]}" var="dataItem">
${dataItem}
</c:forEach>
</c:forEach>
Ver también:
- ¿Dónde se utilizan JavaBeans?
- Mostrar JDBC ResultSet en HTML en la página JSP usando el patrón MVC y DAO
No relacionado con el problema concreto, el atributo <c:forEach var>
no es correcto. No debe darle el mismo nombre que un objeto existente en el alcance. Solo chocaría. Pero eso está sujeto a una nueva pregunta si no puede interpretar el mensaje de error.