Páginas

sábado, 12 de enero de 2013

Primeros pasos con Apache Velocity

En esta entrada vamos a detallar un ejemplo de uso de Apache Velocity. Esta herramienta nos permite generar fácilmente documentos xml, html, sql, csv, txt, etc.

Apache Velocity renderiza una plantilla con ciertos datos. Las plantillas deberán ser generadas previamente en base al lenguaje VTL (Velocity Template Language).

VTL nos permite generar informes muy grandes con poco esfuerzo.

Supongamos que nos interesa enviar el informe siguiente por correo electrónico:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2          200 |
| 2005       T3           50 |
| 2005       T4            5 |
+------+------------+--------+


Como primera aproximación montaríamos una plantilla simple, donde las líneas de contenido fijo aparecen tal cual, mientras que en aquellas líneas donde hay conenido variable (año, trimestre y unidades) hemos insertado unas variables  respetando los espacios en blanco que mantienen el encolumnado.

Las diferentes líneas del informe se generan recorriendo los elementos de la lista $listaVentas, cada elemento de la lista se carga en la variable $venta, y cada venta tiene dos atributos: $venta.trim y $venta.unidaddes.

#***************
Plantilla simple
***************#
+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
#foreach($venta in $listaVentas)
| $anno       $venta.trim         $venta.unidades |
#end
+------+------------+--------+


Seguidamente montaríamos el código java, en donde cabe destacar que iniciamos el motor velocity fijando el encoding tanto de la plantilla de entrada como del documento renderizado a generar:

package org.edu.velocity.app;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class Test {

    public static void main(String[] args) {

        //Instanciamos el motor velocity
        final VelocityEngine ve = new VelocityEngine();
       
        //Definimos el encoding de entrada y salida
        final Properties props = new Properties();
        props.put("output.encoding","UTF-8");
        props.put("input.encoding","UTF-8");
       
        //Inicializamos el motor velocity con el encoding deseado
        ve.init(props);
       
        //Cargamos la plantilla
        final Template t = ve.getTemplate("informe-simple.vm");
        //final Template t = ve.getTemplate("informe-alineado.vm");
       
        //Preparamos los datos
        final List<Object> listaVentas = new ArrayList<Object>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("trim", "T1");
        map.put("unidades", "1000");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T2");
        map.put("unidades", "200");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T3");
        map.put("unidades", "50");
        listaVentas.add(map);
        map = new HashMap<String, String>();
        map.put("trim", "T4");
        map.put("unidades", "5");
        listaVentas.add(map);
       
        //Creamos el contexto y le metemos los datos
        final VelocityContext context = new VelocityContext();
        context.put("listaVentas", listaVentas);
        context.put("anno", "2005");
       
        //Renderizamos la plantilla
        final StringWriter writer = new StringWriter();
        t.merge( context, writer );
       
        //Visualizamos la plantilla
        System.out.println(writer.toString());

}


Al ejecutar este código tendríamos la siguiente salida:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2         200 |
| 2005       T3         50 |
| 2005       T4         5 |
+------+------------+--------+


La salida es casi lo que queríamos, pero al variar la longitud de los números de la última columna, tiene un aspecto incorrecto. Vamos a reajustar la plantilla con un control del tamaño de la variable $venta.unidades. Con lo que la plantilla alineada quedaría:

#*****************
Plantilla alineada
*****************#
+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
#foreach($venta in $listaVentas)
#if($venta.unidades.length()==4)
| $anno       $venta.trim         $venta.unidades |
#{elseif}($venta.unidades.length()==3)
| $anno       $venta.trim          $venta.unidades |
#{elseif}($venta.unidades.length()==2)
| $anno       $venta.trim           $venta.unidades |
#{else}
| $anno       $venta.trim            $venta.unidades |
#end
#end
+------+------------+--------+


Si ejecutamos de nuevo el informe tendremos la salida corregida:

+------+------------+--------+
| Año  | Trimestre  | Ventas |
+------+------------+--------+
| 2005       T1         1000 |
| 2005       T2          200 |
| 2005       T3           50 |
| 2005       T4            5 |
+------+------------+--------+


Librerías.

Para lanzar este ejemplo hemos necesitado las librerías:

velocity-1.7.jar
commons-lang-2.4.jar
commons-collections-3.2.1.jar

Enlaces.

Más información sobre Apache Velocity y VTL en:

http://velocity.apache.org/
http://velocity.apache.org/engine/devel/vtl-reference-guide.html

Conclusiones.

Para generar documentos xml, html, sql, csv y txt, es una herramienta muy potente. La única limitación que le encuentro (sin haberle dedicado mas de una hora al tema), es que si pretendemos generar txt habrá que limitarse a cosas muy simples, dado que en cuanto el documento objetivo es un poco mas complejo la cosa se complica.

No quiero ni pensar qué habría que meter en VTL para generar un informe con varias columnas numéricas que tuviesen que salir alineadas como en el siguiente ejemplo:

+------+-----------+----------+---------+-------+
| Año  | Trimestre | Entradas | Salidas | Stock |
+------+-----------+----------+---------+-------+

| 2005 |     T1    |     1000 |     100 |   900 |
| 2005
|     T2    |      200 |      50 |   150 |
| 2005 |     T3    |       50 |      20 |    30 |
| 2005 |     T4    |        5 |       3 |     2 |
+------+-----------+----------+---------+-------+


La cosa también sería muy compleja si alguien quiere que se generen documentos en txt con justificación completa (es un ejemplo muy rebuscado, me doy cuenta), similares al siguiente ejemplo:

Estimado Juan Español Español.

Nos dirigimos a  vd.  para comunicarle que el
día  17 de  Abril de 2013 a  transferiremos a
la cuenta 0182-0098-XX-XXXXXXXXXX la cantidad
de  1.355,22€ liquidando de ese modo la deuda
pendiente.

En Madrid a 01 de Enero de 2013.

Supongo que las librerías velocity-tools y .

No hay comentarios:

Publicar un comentario