viernes, mayo 23, 2008

DisplayTag y TableDecorator

DisplayTag es una librería comúnmente utilizada en Spring-MVC y facilita muchísimo el despliegue de información en tablas.

TableDecorator es una clase, que extendida, permite customizar la salida y presentación de las propiedades del objeto listado.

Por ejemplo. Tengo el siguiente objeto.

@Entity
public class Partida extends BaseObject implements Serializable {
private static final long serialVersionUID = -3392581174026724271L;

private Long id;
private User user;
private EntidadFederativa estado;
private Intervencion intervencion;
private FuenteFinanciamiento ff;
private CatalogoPartidas partida;
private Double recurso;
private Boolean compraconsolidada;

@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id",nullable=false)
public User getUser() {
return user;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="estado_id",nullable=false)
public EntidadFederativa getEstado() {
return estado;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="intervencion_id",nullable=false)
public Intervencion getIntervencion() {
return intervencion;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="ff_id",nullable=false)
public FuenteFinanciamiento getFf() {
return ff;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="partida_id",nullable=false)
public CatalogoPartidas getPartida() {
return partida;
}

public Double getRecurso() {
return recurso;
}

public Boolean getCompraconsolidada() {
return compraconsolidada;
}

public void setId(Long id) {
this.id = id;
}

public void setUser(User user) {
this.user = user;
}

public void setEstado(EntidadFederativa estado) {
this.estado = estado;
}

public void setIntervencion(Intervencion intervencion) {
this.intervencion = intervencion;
}

public void setFf(FuenteFinanciamiento ff) {
this.ff = ff;
}

public void setPartida(CatalogoPartidas partida) {
this.partida = partida;
}

public void setRecurso(Double recurso) {
this.recurso = recurso;
}

public void setCompraconsolidada(Boolean compraconsolidada) {
this.compraconsolidada = compraconsolidada;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
final Partida other = (Partida) obj;
if (compraconsolidada == null) {
if (other.compraconsolidada != null)
return false;
} else if (!compraconsolidada.equals(other.compraconsolidada))
return false;
if (estado == null) {
if (other.estado != null)
return false;
} else if (!estado.equals(other.estado))
return false;
if (ff == null) {
if (other.ff != null)
return false;
} else if (!ff.equals(other.ff))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (intervencion == null) {
if (other.intervencion != null)
return false;
} else if (!intervencion.equals(other.intervencion))
return false;
if (partida == null) {
if (other.partida != null)
return false;
} else if (!partida.equals(other.partida))
return false;
if (recurso == null) {
if (other.recurso != null)
return false;
} else if (!recurso.equals(other.recurso))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((compraconsolidada == null) ? 0 : compraconsolidada
.hashCode());
result = prime * result + ((estado == null) ? 0 : estado.hashCode());
result = prime * result + ((ff == null) ? 0 : ff.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((intervencion == null) ? 0 : intervencion.hashCode());
result = prime * result + ((partida == null) ? 0 : partida.hashCode());
result = prime * result + ((recurso == null) ? 0 : recurso.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}

/**
* @see java.lang.Object#toString()
*/
public String toString() {
return new ToStringBuilder(this).append("compraconsolidada",
this.compraconsolidada).append("estado", this.estado).append(
"id", this.id).append("intervencion", this.intervencion)
.append("user", this.user).append("ff", this.ff).append(
"recurso", this.recurso)
.append("partida", this.partida).toString();
}

}

y la siguiente tabla


<display:table name="partidaList" class="table"
style="width: 100%" id="partidaList" export="true" pagesize="25"
>
<display:column property="id" media="csv excel xml pdf"
titleKey="partida.id" />
<display:column property="ff" titleKey="partida.ff" />
</display:column>
<display:column property="partida.id" titleKey="partida.id"></display:column>
<display:column property="partida.nombre" titleKey="partida.nombre"></display:column>
<display:column property="recurso" titleKey="partida.recurso"></display:column>
</display:table>



Me despliega los datos de manera muy simple


La columna del recurso (dinero) se ve mal.

Extendemos ahora la clase TableDecorator.


public class WrapperPartida extends TableDecorator {

/**
* DecimalFormat usado para dar formato a getRecurso().
*/
private DecimalFormat moneyFormat;

/**
* Constructor que asigna el formato, según documentación hace más eficiente la clase
*/
public WrapperPartida() {
super();

this.moneyFormat = new DecimalFormat("$ #,###,###.00");
}

/**
* Método para regresar nulos
*
* @return <code>null</code>
*/
public String getNullValue() {
return null;
}

/**
* Damos formato al dinero como un String $ #,###,###.format.
* Estamos tomando directamente del objeto tipo Partida, la propiedad recurso
* @return String
*/
public String getRecurso() {
return this.moneyFormat.format(((Partida) this.getCurrentRowObject())
.getRecurso());
}

}

Ahora agregamos el decorator a la tabla en la declaración y además ponemos el total de los recursos asignados.
  decorator="com.deuxbits.ssaspps.webapp.decorator.WrapperPartida"

Para totalizar los recursos, debemos declarar una variable que almacene los totales.
 varTotals="totals"

y activar la operacion en las columnas que queramos, para este ejemplo, sólo la de recurso.
<display:column property="recurso" titleKey="partida.recurso"
class="textright" total="true"></display:column>

Al final queremos mostrar el total ¿no? para ello utilizamos otro tag de la librería
  <display:footer>
<tr><td>&nbsp;</td><td>&nbsp;</td>
<td>Total</td>
<td class="textright">
<fmt:formatNumber value="${totals.column4}" type="currency" currencyCode="USD" />
</td>
<tr>
</display:footer>


Todo junto queda así:


<display:table name="partidaList" class="table" requestURI="" varTotals="totals"
style="width: 100%" id="partidaList" export="true" pagesize="25"
decorator="com.deuxbits.ssaspps.webapp.decorator.WrapperPartida">

<display:column property="recurso" titleKey="partida.recurso"
class="textright" total="true"></display:column>

<display:footer>
<tr><td>&nbsp;</td><td>&nbsp;</td>
<td>Total</td>
<td class="textright">
<fmt:formatNumber value="${totals.column4}" type="currency" currencyCode="USD" />
</td>
<tr>
</display:footer>

</display:table>


Mostrando la tabla de la siguiente manera:

7 comentarios:

Anónimo dijo...

Muchas gracias.

Martin dijo...

Muy bueno el articulo.. se agradece..

ahora.. una pregunta.. yo quiero hacer lo mismo.. pero cuando quiero sacar la propiedad de la lista dentro del objeto me dice que no esta definida... es decir..
ERROR:Error looking up property "atrasos.codAtraso" in object type "com.persistencia.entities.Vuelo".

el quiere buscar el getter ahi..

no sebas como tengo q hacer?

juparave dijo...

Las columans que estás desplegando en la tabla las puede tomar del decorator, pero si estás totalizando una columna necesitas el getter desde el objeto que listas.

No creo que estés totalizando el codAtraso así que el alguna parte de tu objeto debe de existir el getter para esa propiedad dentro de atrasos.

John dijo...

Miiil graciaas juparave, muy buen aporte !!!

Sin embargo lo que quiero hacer es que dependiendo del valor, solo la celda (no todo el renglon) se ponga de un color u otro (Ej. si el valor es negativo la celda será rojo, de lo contrario será verde). Ya estuve revisando en miles de paginas como hacerlo, pero no mas nada, no logro hacer que funcione : / Alguien que sepa como hacerlo posible? Cualquier aporte será bienvenido. Para información estoy trabajando con Spring-MVC y mi lista es un ArrayList

Saludos a todos.

Tomas dijo...

Buenas John,

tengo el mismo problema que vos, lo pudiste solucionar?

inferno23@gmail.com dijo...

mi problema es q tengo 40 registros y en la pantalla muestro solo 20 por pagina y al sumar solo me muestra el total de la pagina (suma solo los 20)como se puede mostrar total de pagina y total de la lista juntos

Anónimo dijo...

Podrías cambiar los colores, casi me quedo ciego.

Buen artículo :)