Вы находитесь на странице: 1из 26

RichFaces, trabajando con tablas (1)

Introduccin
El problema de la gestin de tablas se describe en el siguiente esquema:

La renderizacin de tablas que muestran gran cantidad de datos acarrea varios problemas: 1. 2. 3. Acceso a la base de datos. Almacenamiento de los registros como objetos Java en memoria. Renderizacin de todos los registros en la pgina que ver el usuario en el navegador.

La biblioteca de componentes JavaServer Faces de JBoss llamada RichFaces proporciona varios componentes para el manejo de tablas avanzado, proporcionando paginacin, ordenacin y filtrado de datos. Estos mecanismos intentan reducir los problemas de renderizacin provocados por la visualizacin de demasiados elementos en una tabla simultaneamente, este concepto ha sido identificado mediante el punto 3. Los componentes RichFaces que vamos a utilizar son:

<rich:dataTable> <rich:column> <rich:dataScroller>

Estos componentes nos permitirn gestionar grandes cantidades de informacin de forma eficiente:

Creando tablas
Introduccin
El componente rich:dataTable permite crear tablas en RichFaces. Este componente es muy parecido al componente <h:dataTable> con dos variaciones:

Skinnability: se aplican estilos sobre las tablas de una forma cmoda y sencilla. Soporte Ajax: este componente es capaz de manejar y generar peticiones y respuestas Ajax. Tambin existen atributos para la gestin de eventos.

<rich:dataTable ...> ... </rich:dataTable>

Los atributos ms importantes del componente son:

value: la coleccin de datos que se va a mostrar. Se hace referencia a sta mediante lenguaje de expresin. var: nombre de la variable sobre la que se itera.

<rich:dataTable value="#{bean1.datos}" var="factura" ...> ... </rich:dataTable>

Importante: se supone que el lector maneja JavaServer Faces, por esa razn, debe estar familiarizado con estos atributos, el lenguaje de expresin, etc.

El componente rich:column
La definicin correcta de la tabla se hace habitualmente mediante el uso de otro componente llamado column. Como su nombre indica, permite crear columnas dentro de la tabla. La informacin que muestra cada columna se incluye dentro de ella, anidando otro componente. Por ejemplo, si se quiere mostrar un texto se anidar un componente <h:outputText>

<rich:dataTable ...> <rich:column> <h:outputText ...></h:outputText> </rich:column> ... </rich:dataTable>

Las facetas de la tabla


La definicin de ttulo, cabecera y pie de tabla se realiza mediante facetas: header, footer y caption. Como se puede ver en el ejemplo anterior, se definen cabeceras para cada columna:

<rich:dataTable ...> <f:facet name="header"> ... </facet> ... </rich:dataTable>

Ejemplo
Se pasa a renderizar una tabla de facturas. stas se encuentran almacenadas en una lista definida en un mbean de JavaServer Faces (debe estar declarado en el fichero de configuracin de JSF).

... public class MBean1 { ... // Lista de facturas que muestra la tabla public List<Factura> facturas; ... }

La clase Factura tiene atributos para cada informacin que se quiere manejar de la factura:

... public class Documento{

private String concepto; private String codigo; private double importe; ... }

La tabla en la vista se construye de la siguiente forma:

... <rich:dataTable value="#{mbean1.facturas}" var="f" ...> <rich:column> <f:facet name="header">

<h:outputText value="Concepto" /> </f:facet> <h:outputText value="#{f.concepto}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Cdigo de la factura" /> </f:facet> <h:outputText value="#{f.codigo}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Importe" /> </f:facet> <h:outputText value="#{f.importe}" /> </rich:column> </rich:dataTable> ...

Paginando tablas
El proceso de paginacin se lleva a cabo mediante el componente <rich:datascroller>. Para realizar la paginacin se utilizan peticiones Ajax. Este componente debe incluirse dentro del pie de la tabla padre o relacionarla mediante su atributo for: - Dentro del pie:

<rich:dataTable ...> <rich:column> ... </rich:column> ... <f:facet name="footer"> <rich:datascroller id="ds"></rich:datascroller> </f:facet> </rich:dataTable>

- Mediante el atributo for: almacena el id de la tabla sobre la que se est actuando.

<rich:dataTable id="tablaEjemplo" ...> <rich:column> ... </rich:column> ... </rich:dataTable> <rich:datascroller id="ds" for="tablaEjemplo" ...></rich:datascroller>

En ambos casos se consigue algo de este estilo:

El componente dataScroller genera una barra numerada que permite recorrer todos los elementos de la tabla.

Ordenando y filtrando tablas


La ordenacin de tablas se realiza trabajando con el atributo sortBy asociado a los componentes <rich:column>. Se muestra a continuacin:

<rich:dataTable value="#{mbean1.facturas}" var="f" ...> <rich:column sortBy="#{f.concepto}"> <f:facet name="header"> <h:outputText value="Concepto" /> </f:facet> <h:outputText value="#{f.concepto}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Cdigo de la factura" /> </f:facet>

<h:outputText value="#{f.codigo}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Importe" /> </f:facet> <h:outputText value="#{f.importe}" /> </rich:column> </rich:dataTable> ...

El proceso de filtrado se lleva a cabo aplicando sobre las columnas, es decir, los componentes <rich:column> el atributo filterBy.

<rich:dataTable value="#{mbean1.facturas}" var="f" ...> <rich:column sortBy="#{f.concepto}" filterBy="#{f.concepto}"> <f:facet name="header"> <h:outputText value="Concepto" /> </f:facet> <h:outputText value="#{f.concepto}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Cdigo de la factura" /> </f:facet> <h:outputText value="#{f.codigo}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="Importe" /> </f:facet> <h:outputText value="#{f.importe}" /> </rich:column> </rich:dataTable> ... ...

Si se aplican ambos conceptos sobre la misma tabla, se obtiene algo as:

Conclusiones
Los componentes para el manejo de tablas de RichFaces, utilizados de forma estndar, nos permiten mejorar las prestaciones de nuestras tablas en cuanto al nmero de elementos renderizados en nuestras pginas simultneamente, pero en ningn caso, nos permite reducir el nmero de objetos almacenados en memoria ni el tipo de consultas que realizo sobre la base de datos. En prximos arttulos se describe este proceso de mejora.

RichFaces, trabajando con tablas (2)


Introduccin
Se quiere trabajar con tablas paginadas que NO tengan que guardar en memoria TODOS los objetos de la tabla, estn siendo mostrados en pantalla o no. De esta forma se optimiza la memoria necesaria para la aplicacin. El modelo presentado en el artculo "RichFaces, trabajando con tablas (1)" maneja un conjunto de datos mediante una lista Java (se modela mediante la interface List). De tal forma que, independiente de la paginacin que se est aplicando, todos los objetos de la tabla se encuentran cargados en memoria. Esto, en muchas ocasiones, no es viable.

La solucin que se plantea en este artculo permite almacenar en memoria SLO los objetos que se estn utilizando en cada momento. Como ya se ha comentado anteriormente, no se trabaja con una implementacin de la interface List. El modelo va a evolucionar para trabajar de una forma ms sofisticada:

<rich:dataTable value="#{modeloImpl}"...> ... </rich:dataTable>

El modelo ser una clase que hereda de SerializableDataModel. Se modifica, a continuacin, el ejemplo inicial descrito en "RichFaces, trabajando con tablas (1)" para que no tengan que cargarse todos los objetos generados como resultado de la consulta en memoria. Adems, vamos a hacer que el MBean utilizado para esta pgina NO tenga que encontrarse en el alcance de sesin:

... public class MBean2 {

private DataModel facturas; ...

public DataModel getFacturas() { return facturas; } public void setFacturas(DataModel facturas) { this.facturas = facturas; } }

Pasamos a inyectar el modelo mediante el fichero de configuracin de JavaServer Faces:

... <managed-bean> <managed-bean-name>paginacion2</managed-bean-name> <managed-bean-class> es.ematiz.paginacion.MBean2 </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>facturas</property-name> <value>#{modeloFacturas}</value> </managed-property> </managed-bean> ...

Nota: el MBean asociado al modelo de datos llamado modeloFacturas ser definido posteriormente. Es importante NO olvidar que vamos a tener que implementar una clase que herede de SerializableDataModel. Para entender de forma adecuada cmo hacerlo, se describen a continuacin las clases que se van a manejar:

La clase DataModel: clase perteneciente a la especificacin JavaServer Faces que permite definir modelos de datos avanzados. La clase ExtendedDataModel: es una clase abstracta que define modelos de datos avanzados. La clase SerializableDataModel: el modelo de datos ser una clase que hereda de sta.

La clase DataModel
Esta clase es una abstraccin de datos que puede utilizarse como fuente de datos para distintos componentes JSF que soportan procesado de filas de sus componentes hijos. La coleccin de datos subyacente de una instancia de DataModel se modela como una coleccin de objetos fila a la que se puede acceder mediante un ndice.

Mtodos:

getRowCount(): nmero de filas de objetos representados por la instancia DataModel. getRowData(): devuelve el objeto representado por la fila seleccionada por el ndice de filas. getRowIndex(): devuelve el ndice de filas. ...

Se recomienda analizar de forma detallada la clase mediante documentacin oficial.

La clase ExtendedDataModel
Es una extensin abstracta de DataModel definida por RichFaces para manejar estructuras de datos complejas.

- La clave o identificador para cada uno de los objetos no tiene que ser un ndice entero. Puede ser cualquier tipo de objeto. Para modelar esta idea se deben implementar los mtodos siguientes adaptndolos a nuestras necesidades:

public abstract void setRowKey(java.lang.Object key) public abstract java.lang.Object getRowKey()

- El mtodo walk() ser el responsable de generar los objetos que va a manejar el componente JSF en la renderizacin.

public abstract void walk( FacesContext context,

DataVisitor visitor, Range range, Object argument) throws java.io.IOException

Este mtodo itera sobre el modelo mediante el patrn visitor para un rango dado. Cada vez que el ciclo de vida JSF necesita recuperar el modelo de datos ejecuta este mtodo, es decir, en una situacin normal se ejecuta tres veces: fase de aplicacin de la peticin, fase de validacin y fase de actualizacin del modelo. - El mtodo getSerializableModel(): un componente de iteracin puede soportar operaciones de guardado de datos en las fases de decodificacin/validacin y actualizacin para evitar llamadas innecesarias al modelo original. Por ejemplo, para evitar peticiones a la base de datos hasta que todos los datos estn validados. Este mtodo se ejecuta una vez en el ciclo de vida estndar JSF, en la fase de renderizacin.

La clase SerializableDataModel
Hereda de ExtendedDataModel aadiendo un nuevo mtodo update() que slo se ejecuta cuando se lanza una accin dentro del componente JSF asociado en la fase de actualizacin del modelo:

Diseo del modelo de datos


Una vez descritas las tres clases importantes que nos permitirn crear el modelo de datos, pasamos a construirlo para nuestro ejemplo de Facturas. Como ya se ha comentado el modelo de datos hereda de la clase SerializableDataModel:

... public class FacturaDataModel extends SerializableDataModel{

// Atributos del modelo de datos private static final long serialVersionUID = 1L;

// Clave o identificador de cada factura. private Integer currentPk; // Mapa que almacena id/Factura para los objetos que estn manejando // la tabla en este momento. private Map<Integer,Factura> wrappedData = new HashMap<Integer,Factura>(); // Lista de los identificadores que est manejando la tabla // en cada caso. private List<Integer> wrappedKeys = null; private FacturaDataProvider dataProvider; private boolean detached = false; ...

- El atributo currentPk representa a la clave primaria del objeto asociado a la tabla que se est manejando. Para el caso de Factura, la clave es de tipo Integer, es por eso que currentPK es de tipo Integer. Si la clave primaria del objeto manejado por la tabla fuera de otro tipo, deberamos cambiar tambin el tipo asociado a este atributo. Por ejemplo, si fuera una cadena de caracteres sera:

private String currentPk;

- El atributo wrappedData es un mapa que debe almacenar pares de datos: identificador nico del objeto y los objetos que maneja la tabla en este momento. - El atributo wrappedKeys almacena los identificadores nicos de cada uno de los objetos que maneja la tabla.

private Map<Integer,Factura> wrappedData = new HashMap<Integer,Factura>();

private List<Integer> wrappedKeys = null;

- El atributo detached es un booleano que vamos a utilizar para indicar cundo hay que recuperar el modelo de datos de la base de datos y cuando NO se debe hacer. Este atributo nos permite diferenciar entre peticiones que renderizan la tabla paginada y peticiones POSTBACK. MUY IMPORTANTE a la hora de optimizar el acceso a la base de datos. - El atributo dataProvider es el objeto Java que realmente se responsabiliza del acceso a base de datos. Posteriormente, se describe el proceso para crear esta clase. El diseo del modelo de datos implica la implementacin los mtodos anteriormente comentados:

Mtodo walk. Mtodo getSerializableModel. Mtodo update. Mtodo getRowCount. Mtodo getRowData.

El mtodo walk()
public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException { // Paso 1: Se recupera el rango de datos con el que trabaja la tabla // paginada. int firstRow = ((SequenceRange)range).getFirstRow(); int numberOfRows = ((SequenceRange)range).getRows();

// Se comprueba si el modelo esta serializado if (detached) { // Paso 2.1: Si el modelo est serializado NO se accede de nuevo // a la base de datos. for (Integer key:wrappedKeys) { setRowKey(key); visitor.process(context, key, argument); } } else { // Paso 2.2: Si el modelo no esta serializado hay que volver a // recuperarlo. wrappedKeys = new ArrayList<Integer>(); // Para recuperar el modelo se actua sobre el proveedor // de datos, dataProvider. for (Factura f:dataProvider.getItemsByRange(firstRow, numberOfRows)) { wrappedKeys.add(f.getCodfactura()); wrappedData.put(f.getCodfactura(), f); visitor.process(context, f.getCodfactura(), argument); } } }

El mtodo getSerializableModel()
public SerializableDataModel getSerializableModel(Range range) { if (wrappedKeys!=null) { detached = true; return this; } else { return null; } }

El mtodo update()
Este mtodo se ejecuta, dentro del ciclo de vida JSF en la fase de actualizacin del modelo, como resultado de una accin dentro de la tabla que, evidentemente, tiene que enviar la tabla como parte de la informacin a procesar en el servidor. Inicialmente este mtodo puede estar vaco:

public void update() {

El mtodo getRowData()
Devuelve el objeto asociado al identificador actual.

public Object getRowData() {

if (currentPk==null) { return null; } else { Factura ret = wrappedData.get(currentPk); if (ret==null) { // Se utiliza el proveedor de datos para recuperar el objeto // asociado a una determinada clave o identificador. ret = getDataProvider().getItemByKey(currentPk); wrappedData.put(currentPk, ret); return ret;

} else { return ret; } } }

El mtodo getRowCount()
Devuelve el nmero de filas total de la informacin con la que se trabaja.

private Integer rowCount; @Override public int getRowCount() { if (rowCount==null) { rowCount = new Integer(getDataProvider().getRowCount()); return rowCount.intValue(); } else { return rowCount.intValue(); } }

El modelo de datos se define en el alcance request.

<managed-bean> <managed-bean-name>modeloFacturas</managed-bean-name> <managed-bean-class> es.ematiz.paginacion.modelo.FacturaDataModel </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>dataProvider</property-name> <value>#{proveedorFacturas}</value> </managed-property> </managed-bean>

El proveedor de datos va a ser definido como MBean y, como se puede ver en el cdigo, ser inyectado en el modelo de datos como una propiedad manejada. Se describe a continuacin el proceso de creacin de dicho proveedor.

El proveedor de datos
Es el objeto responsable de la interaccin con el sistema de almacenamiento sobre el que trabajamos para recuperar la informacin. Esta clase debe implementar la interface DataProvider<T> que se encuentra en el paquete org.richfaces.model. Esta especificacin define los siguientes mtodos:

getItemByKey: devuelve un objeto a partir de su clave. getItemsByRange: devuelve una lista de objetos en funcin de un rango de valores definido como parmetro. getKey: devuelve la clave asociada a un objeto pasado como parmetro. getRowCount: nmero de filas total.

Siguiendo nuestro ejemplo, el proveedor de datos para Facturas sera algo tal que as:

... public class FacturaDataProvider implements DataProvider<Factura>{ // Atributos de la clase private static final long serialVersionUID = 1L; private Integer size = null; private List<Factura> rango; private Map<Integer,Factura> mapa = new HashMap<Integer,Factura>(); ... }

- El atributo size define el nmero de elementos que se manejan. - El atributo rango define el conjunto de objetos que realmente se van a cargar en memoria. - El atributo mapa almacena pares Identificador de objeto, objeto.

El mtodo getItemByKey()
Como su nombre indica, este mtodo debe devolver el objeto asociado a una determinada clave o identificador.

@Override public Factura getItemByKey(Object key) { // Uno de los atributos de la clase es una mapa que almacena pares // claves/Objetos, por lo tanto, teniendo la clave recuperar el objeto // es algo evidente. return mapa.get(key); }

El mtodo getKey()
Este mtodo recupera la clave asociada al objeto pasado como parmetro.

@Override public Object getKey(Factura f) { // Para el caso de la clase Factura, su clave es codigo. return f.getCodigo(); }

El mtodo getItemsByRange()
Es el mtodo ms importante, siendo responsable de la recuperacin de SLO los objetos que va a mostrar la tabla en cada momento, es decir SLO recupera el rango definido mediante los parmetros firstRow y endRow.

public List<Factura> getItemsByRange(int firstRow, int endRow) {

FacturaBD servicio = new FacturaBD(); rango = servicio.findFacturas(firstRow, endRow);

Iterator<Factura> it = rango.iterator(); while (it.hasNext()) { Factura factura = (Factura) it.next(); mapa.put(factura.getCodfactura(), factura); } return rango; }

El mtodo getRowCount()
Este mtodo devuelve como valor de retorno el nmero total de datos con los que trabaja la tabla. Este valor determina el tamao del scroller asociado a la tabla.

@Override public int getRowCount() {

if(size==null){ FacturaBD servicio = new FacturaBD();

size = servicio.getNumFacturas(); } return size.intValue(); }

Declaracin del proveedor en faces-config.xml


El proveedor de datos debe ser un objeto definido en el alcance sesin, vamos a aprovechar el fichero de configuracin de JavaServer Faces para definirlo y posteriormente inyectarlo en el modelo de datos:

<managed-bean> <managed-bean-name>proveedorFacturas</managed-bean-name> <managed-bean-class> es.ematiz.paginacion.modelo.FacturaDataProvider </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>

Como ya se ha comentado anteriormente, el proveedor debe ser inyectado en el modelo de datos. Se muestra de nuevo la estructura que debemos incluir en el fichero de configuracin de JavaServer Faces.

<managed-bean> <managed-bean-name>modeloFacturas</managed-bean-name> <managed-bean-class> es.ematiz.paginacion.modelo.FacturaDataModel </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <managed-property> <property-name>dataProvider</property-name> <value>#{proveedorFacturas}</value> </managed-property> </managed-bean>

Incorporacin en la vista
El modelo de datos definido y su proveedor asociado han sido definidos aprovechando la inyeccin de dependencias de JSF. Para poder utilizarlos en la vista slo debemos utilizar lenguaje de expresin:

<h:form> <rich:dataTable id="tablaFacturas" value="#{paginacion2.facturas}" var="f" rows="5" reRender="scroll01" width="100%"> <rich:column id="concepto"> <f:facet name="header"> <h:outputText value="Concepto"/> </f:facet> <h:outputText value="#{f.concepto}" /> </rich:column> ... </rich:dataTable> <rich:datascroller id="scroll01" for="tablaFacturas" maxPages="5" /> </h:form>

A continuacin se muestra el resultado:

No se cargan en memoria todos los objetos, SLO los que se estn visualizando en la tabla.

Anlisis del ciclo de vida


La primera vez que se quiere visualizar la pgina, el ciclo de vida (como ya hemos comentado anteriormente es ms corto):

Fase de restauracin de la vista. Fase de renderizacin: en esta fase se ejecutan los mtodos del modelo de datos anteriormente descritos. En el caso del mtodo walk(), como la variable detached est a falso, obligatoriamente accede a base de datos y recupera SLO los objetos que va a mostrar la tabla. El nmero de objetos cargados en memoria es mucho menor que en el primero caso. Posteriormente, se ejecuta el mtodo getSerializableModel() que devuelve el modelo serializado poniendo la variable detached a verdadero (esto provoca que cuando se hagan peticiones sobre la pgina -Postbacks- no se recupere el modelo de la base de datos, ya que se encuentra serializado).

Finalmente, se obtiene el resultado de la renderizacin:

Para este caso, las nicas acciones que vamos a poder generar sobre la tabla se realizan mediante el scroller. ste va a lanzar una nica peticin a base de datos en la fase de renderizacin. En las dems fases no se hace nada relacionado con el acceso a base de datos, por lo tanto, todo correcto.

RichFaces, trabajando con tablas (3): ordenacin y filtrado manuales


Introduccin
El uso de los atributos sortBy y filterBy del componente rich:column NO ser vlido cuando se trabaja con modelos de datos complejos como el que se present en el artculo "RichFaces, trabajando con tablas (2)". Se deben implementar mecanismos de ordenacin y filtrado manuales que sean capaces de manejar este modelo paginado. Se van a definir commandLinks dentro de las columnas de la tabla que van a lanzar peticiones Ajax para modificar el orden en el que se muestran los datos dentro del dataTable. Se van a crear inputText para definir mecanismos de filtrado.

Ordenacin manual
Modificaciones en la vista
Para aplicar ordenacin sobre una estructura de datos compleja se debe modificar la renderizacin. Se incorpora una nueva accin dentro de la faceta de cabecera que pasa como parmetro, en la peticin que genera, el campo a partir del cul se va a ordenar. Por ejemplo, si se hace click sobre la columna Cdigo de factura se enviar un parmetro llamado sortField cuyo valor ser codfactura y cuando se genere la respuesta se re-renderizar la tabla paginada:

<h:column> <f:facet name="header"> <a4j:commandLink value="Cdigo de factura" reRender="tabla"> <a4j:actionparam name="sortField" value="codfactura" /> </a4j:commandLink> </f:facet> <h:outputText value="#{f.codfactura}"></h:outputText> </h:column>
En este caso se deben utilizar atributos para optimizar el envo de informacin? ajaxSingle = true? No, la peticin desencadenada por esta accin debe enviar la informacin de la tabla para poder procesarla mediante el ciclo de vida estndar. Algn tipo de renderizacin adicional? Queremos que, una vez que el orden de los datos sea modificado, slo sea rerenderizada la tabla. Los dems contenidos de la pgina deben quedar intactos. Por esta razn, se utiliza en atributo reRender asociado a la tabla.

<rich:dataTable id="tablaFacturas" value="#{paginacion2.facturas}"

var="f" rows="5" reRender="scroll01" width="100%"> <rich:column id="concepto"> <f:facet name="header"> <h:outputText value="Concepto"></h:outputText> </f:facet> <a4j:commandLink id="accion" ajaxSingle="true" limitToList="true"> <h:outputText value="#{f.concepto}" /> </a4j:commandLink> </rich:column> <rich:column> <f:facet name="header"> <a4j:commandLink value="Cdigo de factura" reRender="tablaFacturas"> <a4j:actionparam name="sortField" value="codfactura" /> </a4j:commandLink> </f:facet> <h:outputText value="#{f.codfactura}"></h:outputText> </rich:column>

El mtodo update()
El modelo de datos propuesto en el artculo "RichFaces, trabajando con tablas (2)" incorpora un mtodo llamado update() como responsable de todos los procesos de actualizacin del modelo. Este mtodo se ejecuta, dentro del ciclo de vida JSF en la fase de actualizacin del modelo, como resultado de una accin dentro de la tabla que, evidentemente, tiene que enviar la tabla como parte de la informacin a procesar en el servidor. El caso que estamos analizando cumple todas esas condiciones. Por esta razn, este mtodo nos va a permitir implementar el concepto de ordenacin.

... public void update() { // Codigo para cambiar el criterio de ordenacin. } ...

Se muestra a continuacin cdigo de ejemplo:

@Override public void update() { de ordenacin. // Paso 1: Se comprueba si se aplica criterio

if(getCriterioOrdenacion()!=null){ // Paso 2: Se recupera al criterio de ordenacin a aplicar. final String nuevoCriterio = getCriterioOrdenacion().toString(); // Paso 3: Se comprueba si el criterio de ordenacin es igual al que est activo. if(nuevoCriterio.equals(dataProvider.getOrdenacion())){

// Paso 4: Si el criterio de ordenacin es el mismo, debemos cambiar // el orden.

dataProvider.setDescendente(!dataProvider.isDescendente()); } dataProvider.setOrdenacion(nuevoCriterio); } // El atributo detached indica si el modelo de datos est serializado o si hay // que volver a la base de datos a recuperar la informacin de nuevo. // En el caso de un cambio de ordenacin, debemos lanzar una nueva consulta. detached = false; }

Como se ha podido ver en el cdigo, se crea y utiliza un mtodo auxiliar llamado getCriterioOrdenacion para manejar el criterio de ordenacin:

protected Object getCriterioOrdenacion(){ // Paso 1: Se recupera el contexto JSF final FacesContext contexto = FacesContext.getCurrentInstance(); // Paso 2: Se obtiene el parametro pasado en la peticin. final Object o = contexto.getExternalContext().getRequestParameterMap().get("sortField"); return o; }

El mtodo getItemsByRange del proveedor


Lgicamente, este mtodo debe ser modificado para manejar el concepto de ordenacin. Por ejemplo

servicioContabilidad.findAllPaginandoOrdenando(inicio, tam, asc, propiedad);

Anlisis del ciclo de vida


La primera vez que se quiere visualizar la pgina, el ciclo de vida (como ya hemos comentado anteriormente es ms corto):

Fase de restauracin de la vista. Fase de renderizacin: En esta fase se ejecutan los mtodos del modelo de datos anteriormente descritos. En el caso del mtodo walk(), como la variable detached est a falso, obligatoriamente accede a base de datos y recupera SLO los objetos que va a mostrar la tabla. El nmero de objetos cargados en memoria es mucho menor que en el primero caso. Posteriormente, se ejecuta el mtodo getSerializableModel() que devuelve el modelo serializado poniendo la variable detached a verdadero (esto provoca que cuando se hagan peticiones sobre la pgina -Postbacks- no se recupere el modelo de la base de datos, ya que se encuentra serializado).

Una vez que la pgina se renderiza, se muestra:

Al hacer click sobre el enlace Cdigo de factura se genera una peticin al servidor. En ese caso se desencadena un ciclo de vida completo:

La peticin es de tipo POSTBACK, es decir, el modelo est serializado y la variable detached est a true, por lo tanto, aunque se ejecute el mtodo walk() del modelo NO se lanzan consultas a la base de datos. Cuando se llega a la fase de actualizacin se ejecuta el mtodo update(). ste cambia el criterio de ordenacin y pone la variable detached a falso. En la fase de renderizacin, como detached est a falso, cuando se ejecuta el mtodo walk() S se accede a la base de datos aplicando el criterio de ordenacin seleccionado. Como en la vista el atributo reRender est asociado a la tabla, sta vuelve a renderizarse con los nuevos valores.

Filtrado manual
Conceptualmente, este proceso es muy parecido al de ordenacin. Se debe modificar la vista para incorporar un campo que acte como filtro y, posteriormente, se debe modificar el modelo de datos que proporciona registros a la tabla para que cuando se active el filtro acte en consecuencia.

Modificaciones en la vista
Se incorpora un campo de texto que genera peticiones AJAX para activar el proceso de filtrado:

... <rich:column id="concepto"> <f:facet name="header"> <h:outputLabel value="Concepto" for="filtroConcepto"></h:outputLabel>

<h:inputText id="filtroConcepto" value="#{paginacion2.facturas.dataProvider.filtroConcepto}" style="width:90px" > <a4j:support event="onblur" reRender="tablaFacturas,scroll01" ajaxSingle="true" limitToList="true"> </a4j:support> </h:inputText> </f:facet> <h:outputText value="#{f.concepto}" /> </rich:column> ...

Modificaciones en el mtodo getItemsByRange()


Se debe modificar este mtodo para que sea capaz de manejar filtros:

... rango = servicioContabilidad. findAllPaginandoOrdenandoFiltrado( firstRow, endRow, !descendente, ordenacion, filtroConcepto); ...

El resultado de estas modificaciones generan la siguiente vista:

Si se escribe en el filtro se genera un filtrado:

Вам также может понравиться