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: