COMO MANEJAR TABLAS DE DATOS CON JSF
Introducción
En este tutorial vamos a probar
las múltiples posibilidades que ofrece la extension
del componente DataTable que realiza la implementación Tomahawk
de MyFaces.
Herramientas utilizadas
- Sistema
operativo: Windows XP Professional. - Servidor
Web: Apache TomCat 5.5.9 - Entorno
de desarrollo: Eclipse 3.1.1 con ExadelStudio-3[1].0.5
Preparamos el entorno
Lo primero que hacemos es crear la infraestructura básica
para trabajar con JSF; para ello:
- Creamos
un nuevo proyecto JSF en Eclipse, al que llamaremos PruebaTablas. Indicaremos durante la creación
que el entorno JSF es MyFaces 1.1.0. La
estructura de directorios que nos queda es la siguiente:
- Creamos
el fichero index.jsp en el directorio WebContent; hará una redirección a la
página home.jsp, que construiremos más
adelante:
<%@ taglib uri=»http://myfaces.apache.org/extensions» <!doctype html public «-//w3c//dtd html 4.0 <html> <head>AUTENTIA- <body> <jsp:forward page=»home.jsf» </body> </html> |
- Preparamos
el bean ListaUsuariosBean
que proporcionará un listado de objetos de tipo Usuario:
package com.autentia.pruebaTablas; import java.util.ArrayList; import java.util.List; /** * Bean encargado * @author AUTENTIA */ public class ListaUsuariosBean { private List listaUsuarios; /** Constructor */ public ListaUsuariosBean() { listaUsuarios=new ArrayList(); } /** Devuelve una lista de public List getListaUsuarios() { if(listaUsuarios.size()==0) listaUsuarios = Usuario.getListaTemporal(); return } } |
- Creamos
las clases de apoyo Usuario y Perfil
|
package com.autentia.pruebaTablas; import java.util.ArrayList; import java.util.List; /** * Clase que representa un usuario * @author Bea */ public class Usuario { /** private /** private /** private String nombre; /** Perfil */ private /** Constructor */ public { this.login=login; this.password=password; this.nombre=nombre; this.perfil=perfil; } public return } public void setLogin(String login) { this.login = login; } public return }
public this.nombre = nombre; } public return } public this.password = password; } public return perfil; } public void setPerfil(Perfil perfil) { this.perfil } /** * Devuelve una lista «a pelo» de */ public { List for(int i=0;i<200;i++) { Perfil unPerfil = null; if(i%2==0) unPerfil = new Perfil(Perfil.ADMINISTRADOR); else unPerfil = new Perfil(Perfil.USUARIO_CONSULTAS);
lista.add(new Usuario(«unLogin_»+i,»unaPassword_»+i, } return } } |
package com.autentia.pruebaTablas; /** * Clase que representa el rol de un usuario * @author AUTENTIA */ public class Perfil { /** Perfiles predefinidos */ public static final int public static final int USUARIO_CONSULTAS=2;
/** Código del perfil */ private /** Descripción del perfil */ private /** Constructor */ public { this.codigo=codigo; } public int getCodigo() { return } public void setCodigo(int codigo) { this.codigo } public String getDescripcion() { if(codigo==Perfil.ADMINISTRADOR) descripcion=»Administrador»; else descripcion=»Usuario de consultas»; else descripcion=»Perfil desconocido»; return descripcion; } public this.descripcion = descripcion; } } |
|
- Incluímos en el fichero descriptor de JSF el bean ListaUsuariosBean; para
ello editamos el fichero WEB-INF/examples–config.xml y añadimos las siguientes líneas:
<managed–bean> <description>Bean encargado <managed-bean-name>listaUsuariosBean</managed-bean-name> </managed–bean> |
- Creamos
un fichero de recursos en el directorio com.autentia.pruebasTablas
llamado recursos_es (sólo lo voy a
implementar en castellano):
# FICHERO DE RECURSOS EN ESPAÑOL listapaginada_login=Login listapaginada_nombre=Nombre listapaginada_perfil=Perfil listapaginada_edad=Edad listapaginada_fecha=Fecha listapaginada_info={0} usuarios encontrados, |
- Y por
último un fichero de estilos en WebContent/css llamado estilos.css
para que las tablas queden chulas:
.scrollerTable { font-family : Tahoma; font-size: 11px; color: padding: 0; cellpading:0; cellspacing:0; border-style: solid; border-width: 1px; border-color:#EBEADB; width: 600px; } .tablapaginacion { font-family : Tahoma; font-size: 11px; color: padding: 0; cellpading:0; cellspacing:0; width: 600px; align:center; } .standardTable_Header { color: background-color: padding: 0; cellpading:0px; cellspacing:0px; text-align: left; border-right: #D9D7BB 1px solid; border-bottom: #D9D7BB 2px double; height:20; } .columna_abajoderecha { background-color: border-bottom: #D9D7BB 1px solid; border-right: #D9D7BB 1px solid; } .columna_abajo { background-color: border-bottom: #D9D7BB 1px solid; } .scroller { padding-left:150px; } .paginator { font-family : Tahoma; font-size: 11px; } |
También hemos añadido algunas
imágenes a nivel de WebContent/images para los botones de adelante/atrás/último….
Primer ejemplo: una
tabla con “paginación”
Lo de paginación lo ponemos entre comillas porque realmente
no vamos a hacer una paginación real; en este ejemplo tendremos todos los datos
en memoria y mostraremos la porción de información que el usuario solicite.
Creamos la página listaPaginada.jsp
dentro del directorio WebContent. El componente que
nos va a pintar el listado es dataTable:
<%@ page <%@ taglib <%@ taglib <%@ taglib uri=»http://myfaces.apache.org/tomahawk» <html> <!– * Ejemplo de lista paginada. AUTENTIA * */ //–> <head> <meta <title>AUTENTIA <link rel=»stylesheet» type=»text/css» </head> <body> <f:view> <f:loadBundle <h:panelGroup <t:dataTable styleClass=»scrollerTable« headerClass=»standardTable_Header« footerClass=»standardTable_Header« columnClasses=»columna_abajoderecha,columna_abajoderecha,columna_abajo» var=»usuario» value=»#{listaUsuariosBean.listaUsuarios}» preserveDataModel=»false» rows=»10″ > <h:column> <f:facet <h:outputText value=»#{mensajes[‘listapaginada_login‘]}» </f:facet> <h:outputText </h:column>
<h:column> <f:facet <h:outputText value=»#{mensajes[‘listapaginada_nombre‘]}» </f:facet> <h:outputText </h:column>
<h:column> <f:facet <h:outputText value=»#{mensajes[‘listapaginada_perfil‘]}» </f:facet> <h:outputText value=»#{usuario.perfil.descripcion}» /> </h:column>
</t:dataTable>
<h:panelGrid columnClasses=»standardTable_ColumnCentered» > <t:dataScroller for=»data» fastStep=»10″ pageCountVar=»pageCount« pageIndexVar=»pageIndex« styleClass=»scroller« paginator=»true» paginatorMaxPages=»9″ paginatorTableClass=»paginator« paginatorActiveColumnStyle=»font-weight:bold;»> <f:facet <t:graphicImage </f:facet> <f:facet <t:graphicImage </f:facet> <f:facet <t:graphicImage </f:facet> <f:facet <t:graphicImage </f:facet> <f:facet <t:graphicImage </f:facet> <f:facet <t:graphicImage </f:facet> </t:dataScroller> <t:dataScroller for=»data» rowsCountVar=»rowsCount« displayedRowsCountVar=»displayedRowsCountVar« firstRowIndexVar=»firstRowIndex« lastRowIndexVar=»lastRowIndex« pageCountVar=»pageCount« pageIndexVar=»pageIndex« > <h:outputFormat <f:param <f:param <f:param <f:param <f:param <f:param </h:outputFormat> </t:dataScroller> </h:panelGrid> </h:panelGroup> </f:view> </body> </html>
|
Como vemos, el
componente que pinta la tabla es la extensión DataTable
de Tomahawk. Toda la información disponible acerca de este componente la
podemos encontrar en
http://myfaces.apache.org/tomahawk/extDataTable.html
Añade al componente estándar DataTable de JSF las
funcionalidades de:
- guardar el
estado de los datos que componen la tabla entre idas y venidas al servidor
durante la paginación. Esto es útil en el caso de estar efectuando una
paginación real, donde por cada página solicitada se hace un consulta a base de datos, y donde no nos interesa
que los datos hayan podido actualizarse en medio del proceso de
paginación. - Posibilidad de
ordenar la tabla en función de la cabecera que seleccionemos. Un ejemplo
de esto lo veremos más adelante.
En este primer
ejemplo no he añadido ninguna funcionalidad nueva con respecto al DataTable estándar; con el atributo
value=»#{listaUsuariosBean.listaUsuarios}»
Proporciono al componente el listado sobre el que iterar, con
var=»usuario»
estoy especifico la variable donde el componente debe
dejar el objeto Usuario en cada iteración, y directamente accedo a las
variables de usuario, que deben tener por supuesto sus métodos setter y setter
para que la cosa funcione.
La “paginación” se consigue con el componente DataScroller. En principio
funciona con cualquier componente UIData, que debe estar identificado con un id que debe ser
proporcionado en el atributo for de DataScroller. Los atributos pageCountVar, pageIndexVar son variables donde
se almacenan respectivamente el número de páginas total y la página por la que vamos. Estos atributos
tienen una ámbito request. El atributo fastStep hace referencia al número de páginas que se pueden
saltar cuando especificamos un fastforward y un fastrewind.
La pinta que tiene la página una vez desplegada en Tomcat
es:
Segundo ejemplo: una
tabla “ordenable”
Siguiendo con el ejemplo del listado de usuarios, vamos a intentar
conseguir que cuando se seleccionen las cabeceras, el listado se reordene por
el campo que hayamos seleccionado. Para este ejemplo vamos a añadir dos nuevos
campos a la clase de Usuario: edad,
de tipo entero y fechaNacimiento
de tipo Date.
1. Incorporamos
los nuevos campos a la clase Usuario
…… public class Usuario {
/** Edad*/ private int /** Fecha de nacimiento */ private Date fechaNacimiento; /** Constructor */ public Date fechaNacimiento) { this.login=login; this.password=password; this.nombre=nombre; this.perfil=perfil; this.edad=edad; this.fechaNacimiento=fechaNacimiento; } …. /** * Devuelve una lista «a pelo» de */ public static List getListaTemporal() { List lista = new ArrayList(); int edad = 5; for(int i=0;i<50;i++) { Perfil unPerfil = null; if(i%2==0) unPerfil = new else unPerfil = new Perfil(Perfil.USUARIO_CONSULTAS); if(edad>=70) edad -=i; else if(edad<70) edad +=i; Usuario usuario = new Usuario(«unLogin_»+i, «unaPassword_»+i, «Un nombre unPerfil, edad, Utilidades.sumarDias(Utilidades.getTodayDateD(),(i+1)));
lista.add(usuario); } return lista; } } |
He creado la clase com.autentia.pruebaTablas.Utilidades,
con utilidades para manipular fechas:
package com.autentia.pruebaTablas; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * Clase de utilidades * @author AUTENTIA */ public class Utilidades { /** Suma los días pasados como parámetro a la fecha public static Date sumarDias(Date { //Recupero un calendar Calendar _calendar = dateToCalendar( //Realizo la operación de añadido _calendar.add( Calendar.DAY_OF_YEAR, dias ); //Devuelvo la fecha return ( _calendar.getTime() ); } /** * Método que */ public static { //Recupero un GregorianCalendar GregorianCalendar _gregorianCalendar.setTime( //Devuelvo el Calendar return( }
/** * Devuelve la */ public static Date getTodayDateD() { GregorianCalendar f1=new GregorianCalendar(); return f1.get(GregorianCalendar.MONTH), f1.get(GregorianCalendar.DAY_OF_MONTH), 0,0).getTime(); } /** * Da formato a */ public static String formatDate(Date { if(d == return else { SimpleDateFormat formatoTmp return } } } |
2. Infraestructura
de clases para efectuar la ordenación
Creamos una clase
abstracta base que reciba la petición de ordenación del listado desde el
componente. Debe tener un método llamado sort con un parámetro que es el
nombre de la columna por la que el usuario ha solicitado ordenar la tabla:
package com.autentia.pruebaTablas; /** * Clase que ordena tablas de datos * @author AUTENTIA * */ public abstract class ListaOrdenada { /** Nombre de la private /** Indicador de si private /** Constructor */ public { columna=defColumna; ascendente=esOrdenacionAscendente(defColumna); } /** * Ordena la lista */ protected abstract void sort(String columna, boolean ascendente); /** * Devuelve true */ protected /** * Método al que invoca el * ordenar la lista */ public { if { throw }
if { // La columna actual es // en sentido contrario ascendente = !ascendente; } else { //Ordena en el sentido columna = columnaAOrdenadar; ascendente = esOrdenacionAscendente(columna); } sort(columna, } public return ascendente; } public void setAscendente(boolean ascendente) { this.ascendente = ascendente; } public String getSort() return columna; } public void setSort(String this.columna = columna; }
} |
Y ahora modificamos la clase ListaUsuariosBean para que sepa ordenarse por el campo que
el usuario solicite. Para ello la hacemos heredar de la clase abstracta ListaOrdenada, e
implementa los métodos sort
y esOrdenacionAscendente:
package com.autentia.pruebaTablas; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;
import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent;
import org.apache.myfaces.custom.datascroller.ScrollerActionEvent; /** * Bean encargado * @author AUTENTIA */ public class ListaUsuariosBean extends ListaOrdenada { private List listaUsuarios;
/** Nombres de los campos public static String public public public public
/** public { // El campo por el que super(NOMBRE_LOGIN); if(listaUsuarios.size()==0) listaUsuarios = Usuario.getListaTemporal(); } /** Devuelve una lista de usuarios public List getListaUsuarios() { sort(getSort(), isAscendente()); return /** * Devuelve true */ protected { return true; } /** * Ordena una lista de usuarios por un determinado * orden */ protected { Comparator comparator { { Usuario u1 = (Usuario)o1; Usuario u2 = (Usuario)o2; if else return u1.getPerfil().getDescripcion().compareTo(u2.getPerfil().getDescripcion()) : u2.getPerfil().getDescripcion().compareTo(u1.getPerfil().getDescripcion()); else return else } }; Collections.sort(listaUsuarios,comparator); } } |
Y creamos la página para completar el ejemplo, a la que llamaremos listaOrdenable.jsp:
<%@ page session=»false» contentType=»text/html;charset=utf-8″%> <%@ taglib uri=»http://java.sun.com/jsf/html» <%@ taglib uri=»http://java.sun.com/jsf/core» <%@ taglib uri=»http://myfaces.apache.org/tomahawk»
<html>
<!– * Ejemplo de lista paginada. AUTENTIA * http://www.autentia.com */ //–> <head> <meta <title>AUTENTIA <link rel=»stylesheet» type=»text/css» </head> <body>
<f:view> <f:loadBundle <h:panelGroup <t:dataTable styleClass=»scrollerTable« headerClass=»standardTable_Header« footerClass=»standardTable_Header« rowClasses=»standardTable_Row1,standardTable_Row2″ columnClasses=»columna_abajoderecha,columna_abajoderecha,columna_abajo» var=»usuario» value=»#{listaUsuariosBean.listaUsuarios}» sortColumn=»#{listaUsuariosBean.sort}» sortAscending=»#{listaUsuariosBean.ascendente}» preserveDataModel=»true« preserveSort=»true» >
<h:column> <f:facet <t:commandSortHeader <f:facet <t:graphicImage value=»images/ascending-arrow.gif» rendered=»true» </f:facet> <f:facet <t:graphicImage value=»images/descending-arrow.gif» rendered=»true» </f:facet> <h:outputText </t:commandSortHeader> </f:facet> <h:outputText </h:column>
<h:column> <f:facet <t:commandSortHeader columnName=»nombre» arrow=»false»> <f:facet name=»ascending»> <t:graphicImage value=»images/ascending-arrow.gif» rendered=»true» </f:facet> <f:facet name=»descending»> <t:graphicImage value=»images/descending-arrow.gif» rendered=»true» </f:facet> <h:outputText </t:commandSortHeader> </f:facet> <h:outputText </h:column>
<h:column> <f:facet <t:commandSortHeader columnName=»perfil» arrow=»false»> <f:facet name=»ascending»> <t:graphicImage value=»images/ascending-arrow.gif» rendered=»true» </f:facet> <f:facet name=»descending»> <t:graphicImage value=»images/descending-arrow.gif» rendered=»true» </f:facet> <h:outputText </t:commandSortHeader> </f:facet> <h:outputText </h:column>
<h:column> <f:facet <t:commandSortHeader columnName=»edad» arrow=»false»> <f:facet name=»ascending»> <t:graphicImage value=»images/ascending-arrow.gif» rendered=»true» </f:facet> <f:facet name=»descending»> <t:graphicImage value=»images/descending-arrow.gif» rendered=»true» </f:facet> <h:outputText </t:commandSortHeader> </f:facet> <h:outputText </h:column>
<h:column> <f:facet <t:commandSortHeader columnName=»fecha» arrow=»false»> <f:facet name=»ascending»> <t:graphicImage value=»images/ascending-arrow.gif» rendered=»true» border=»0″/> </f:facet> <f:facet name=»descending»> <t:graphicImage value=»images/descending-arrow.gif» rendered=»true» </f:facet> <h:outputText </t:commandSortHeader> </f:facet> <h:outputText </h:column> </t:dataTable> </h:panelGroup> </f:view> </body> </html>
|
El componente commandSortHeader trabaja únicamente dentro de componentes DataTable y es una extensión del componente
estándar CommandLink.
Es el que posibilita que la columna cabecera de la tabla sea ordenable a través del atributo columnName que identifica el
atributo de la lista por el que queremos ordenar la tabla.
Hola, existe alguna forma de imprimir el dataTable completo, pues la función script que utilizo actualmente solo me imprime la página actual ya que el dataTable tiene paginación