Ir al contenido principal

FREEMARKER VS VELOCITY

Hoy nos ponemos en faena para comparar dos conocidos motores de plantillas: FreeMarker y Velocity. Veremos las ventajas de utilizar uno contra otro y como siempre un ejemplo sencillo de cada uno de los motores con Eclipse y Java. Vosotros decidiréis cual utilizar para vuestro proyecto en cuestión. 

Utilizando tanto un motor como el otro podremos realizar nuestras vistas o informes dinámicos mediante plantillas pasando los datos mediante un programa en Java (puede incluso utilizarse para sustituir a las JSPs). También nos permitirán generar salidas para diferentes formatos de archivo: HTML, RTF, XML, etc... y ser  integrados en aplicaciones web dependientes de un servidor como en aplicaciones 'standalone'.

Imagen: memegenerator




Velocity vs FreeMarker


Velocity es un motor más simple, sin embargo, con FreeMarker se pueden realizar algunas tareas que con Velocity es imposible de realizar, además de tener un lenguaje de plantillas más potente.


Algunas tareas complejas comunes a muchas aplicaciones están implementadas en el core de FreeMarker, sin embargo, en Velocity no es así y deberemos utilizar soluciones como añadir objetos java a nuestras plantillas (lo que viola la idea del patron MVC de no incluir código en nuestras vistas). 

Una ventaja de Velocity es que cuenta con el soporte de una mayor comunidad de usuarios, por lo que será fácil dar solución a los problemas con los que nos vayamos encontrando por el camino. Según los autores de FreeMarker, este motor no necesitará de tanto soporte debido a que muchas características que querremos incorporar a nuestras aplicaciones ya las tendremos implementadas en el core.

Como siempre, que el sentido común decida por vosotros. Dependerá del tamaño de vuestra aplicación y lo que queráis hacer con el motor de plantillas en la misma. 

Para descargar la última versión de FreeMarker pulsa aquí y para descargar la última versión de Velocity aquí.


Ejemplo con FreeMarker

Nuestro proyecto resultante en Eclipse debe tener la siguiente estructura:



Lo primero que hacemos es crear nuestras plantillas auxiliares de FreeMaker con extensión .ftl, en nuestro caso, serán header.ftl y footer.ftl. La carpeta para crearlas será templates/common

header.ftl

<title>Tutoriales de JPASCU: ${mensaje1}</title>
<body> 

footer.ftl

</body> 

Posteriormente creamos nuestra plantilla principal main.ftl en el directorio templates. En ella incluimos las otras plantillas. A partir de ella el motor de FreeMarker genera una página HTML con los valores que se pasan desde una clase Java.

main.ftl



<#include "./common/header.ftl"> 
<#if container??>
  <div id="${container}">
<#else>
  

<div id="default">
</#if>


<ul>
<#list jugadores as jugador>
<li>${jugador_index + 1}.${jugador.getName()}</li>
</#list>
</ul>
<h1>
${mensaje2.getName()}</h1>
</div>
<#include "./common/footer.ftl">

Destacamos tres puntos en el código de la plantilla:

  • Utilizamos la directiva <#include> para incluir otras plantillas
  • Podemos utilizar condiciones para poner un código HTML u otro dependiendo de las variables pasadas desde Java. Por ejemplo, <#if container??> es verdadero si la variable container es pasada al motor de FreeMaker. Si no existe la expresión será falsa. OJO: el ?? no funciona en versiones antiguas de FreeMaker.
  • También podemos utilizar bucles y llamar a métodos de objetos Java desde nuestra plantilla .ftl.


Por último, creamos las clases Java, una clase holder (podría ser un String) y la clase de prueba en la que creamos una instancia del motor y le pasamos las variables para que haga el 'merge' con la plantilla. El código Java de las clases es el siguiente:

JugadorFutbol.java

package es.jpascu.engine.freemarker;

public class JugadorFutbol {

 private String name;

 public JugadorFutbol(String name) {
  super();
  this.name = name;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}



TestFreeMaker.java


package es.jpascu.engine.freemarker;

import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

public class TestFreeMarker {

  public static void main(String[] args) {

    // Creamos la configuración
    Writer file = null;
    Configuration cfg = new Configuration();

    try {
      // Seleccionamos el directorio donde se encuentran nuestras plantillas
      cfg.setDirectoryForTemplateLoading(new File("templates"));
      // Cargamos las plantillas
      Template template = cfg.getTemplate("main.ftl");

      // Pasamos los parámetros
      Map input = new HashMap();
      input.put("mensaje1", "Ejemplo con FreeMarker");
      input.put("container", "test");

   
      List jugadores = new ArrayList();

      jugadores.add(new JugadorFutbol("Messi"));
      jugadores.add(new JugadorFutbol("Iniesta"));
      jugadores.add(new JugadorFutbol("Xavi"));
      jugadores.add(new JugadorFutbol("Villa"));
      jugadores.add(new JugadorFutbol("CR7"));

      input.put("jugadores", jugadores);

      JugadorFutbol exampleObject = new JugadorFutbol("¿Pero qué equipo es este?");
      input.put("mensaje2", exampleObject);

      // Escribimos en un fichero HTML
      file = new FileWriter(new File("output.html"));
      template.process(input, file);
      file.flush();

      // Escribimos en la salida estandar
      Writer out = new OutputStreamWriter(System.out);
      template.process(input, out);
      out.flush();

    } catch (Exception e) {
      System.out.println(e.getMessage());

    } finally {
      if (file != null) {
        try {
          file.close();
        } catch (Exception e2) {
        }
      }
    }

  }
} 

En la clase TestFreeMaker cabe destacar lo siguiente:


  • Cargamos la configuración (cfg) del motor con la clase freemarker.template.Configuration.
  • Podemos seleccionar el directorio de plantillas con cfg.setDirectoryForTemplateLoading
  • Cargamos la plantilla con  cfg.getTemplate("main.ftl")
  • Generamos una salida con  template.process(input, file), donde input es un map de tipo parámetro-valor con los valores con los que queremos rellenar nuestra plantilla y file es un stream de salida (salida estandar, fichero HTML, fichero RTF...).

Ejemplo con Velocity

Nuestro proyecto resultante en Eclipse debe tener la siguiente estructura:




Lo primero que hacemos es crear nuestras plantillas auxiliares de Velocity con extensión .vm, en este ejemplo serán header.vm y footer.vm

header.vm


<title>Tutoriales de JPASCU: $mensaje1</title>
<body>

footer.vm

</body>

Posteriormente creamos nuestra plantilla principal main.vm. En ella incluimos las otras plantillas. A partir de ella el motor de Velocity genera una página HTML con los valores que se pasan desde una clase Java.

main.vm



#parse("header.vm")
#if ($container)
  <div id="$container">
#else
  <div id="default">
#end
<ul>
#set ($counter = 0)
#foreach ($jugador in $jugadores)
 #set ($counter = $counter + 1)
<li>$counter.$jugador.getName()</li>
#end
</ul>
<h1>
$mensaje2.getName()</h1>
</div>
#parse("footer.vm")

Veamos ahora las diferencias de notación con FreeMaker:

  • Utilizamos la directiva #parse para incluir otras plantillas con variables. Si queremos incluir alguna plantilla con texto o código HTML estático podemos utilizar #include.
  • También podemos utilizar condiciones para poner un código HTML u otro dependiendo de las variables pasadas desde Java. Utilizamos la directiva #if para realizar una comparación de una variable. Deberemos cerrar las sentencias en las plantillas con #end.
  • También podemos utilizar bucles con la sentencia #foreach y llamar a métodos de objetos Java desde nuestra plantilla .vm con la notación punto igual que en FreeMaker.

Por último, creamos las clases Java, una clase holder (podría ser un String) y la clase de test en la que creamos una instancia del motor de Velocity y le pasamos las variables para que haga el 'merge' con la plantilla, igual que en el caso anterior. El código Java de las clases es el siguiente:

JugadorFutbol.java

package es.jpascu.engine.freemarker;

public class JugadorFutbol {

 private String name;

 public JugadorFutbol(String name) {
  super();
  this.name = name;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}


TestVelocity.java


package es.jpascu.engine.velocity;

import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

public class TestVelocity {

 public static void main(String[] args) {

  Writer file = null;
  /* Inicializamos el motor de Velocity */
  VelocityEngine ve = new VelocityEngine();
  ve.init();

  try {

   // Cargamos las plantillas

   Template t = ve.getTemplate("main.vm");

   // Creamos el contexto donde pasaremos los parámetros
   VelocityContext context = new VelocityContext();

   // Pasamos los parámetros
   Map input = new HashMap();
   context.put("mensaje1", "Ejemplo con Velocity");
   context.put("container", "test");

   List jugadores = new ArrayList();

   jugadores.add(new JugadorFutbol("Messi"));
   jugadores.add(new JugadorFutbol("Iniesta"));
   jugadores.add(new JugadorFutbol("Xavi"));
   jugadores.add(new JugadorFutbol("Villa"));
   jugadores.add(new JugadorFutbol("CR7"));

   context.put("jugadores", jugadores);

   JugadorFutbol exampleObject = new JugadorFutbol(
     "¿Pero qué equipo es este?");
   context.put("mensaje2", exampleObject);

   // Escribimos en un fichero HTML
   file = new FileWriter(new File("output.html"));
   t.merge(context, file);
   file.flush();

   // Escribimos en la salida estandar
   Writer out = new OutputStreamWriter(System.out);
   t.merge(context, out);
   out.flush();

  } catch (Exception e) {
   System.out.println(e.getMessage());

  } finally {
   if (file != null) {
    try {
     file.close();
    } catch (Exception e2) {
    }
   }
  }

 }
}


En la clase TestVelocity  cabe destacar lo siguiente:


  • Inicializamos el motor de Velocity (org.apache.velocity.app.VelocityEngine)
  • El directorio de plantillas lo configuramos en el archivo de configuración de Velocity velocity.properties, en el que también configuramos otras propiedades del motor.
  • Cargamos la plantilla con   ve.getTemplate("main.vm")
  • Creamos el contexto que encapsulara los parámetros que le pasaremos al motor de Velocity para generar la salida.
  • Generamos una salida con  t.merge(context, file), donde context es el objeto Contexto de Velocity (org.apache.velocity.VelocityContext) de tipo parámetro-valor con los valores con los que queremos rellenar nuestra plantilla y file es un stream de salida (salida estandar, fichero HTML, fichero RTF...).


Por último, os muestro el contenido del fichero velocity.properties, en el que le decimos al motor que cargue la plantillas del classpath:

velocimacro.library=macros/VM_global_library.vm

resource.loader=classpath 
classpath.resource.loader.description=Velocity Classpath Resource Loader 
classpath.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader 
classpath.resource.loader.cache=true 
classpath.resource.loader.modificationCheckInterval=2


Espero que el ejemplo sea útil para que profundicéis en el mundo de los motores de plantillas.

Ahh, se me olvidaba, la página resultante para el caso de Velocity es la siguiente:




Salu2.




Comentarios

Publicar un comentario

Entradas populares de este blog

Soluciones Alchemy Classic 389 elementos

Hace algún tiempo salió una actualización del Juego Alchemy Classic en la que aparecían más elementos (389 en lugar de 238). Aparte de añadir elementos mejoran algunas traducciones en castellano y mejoran la interfaz, aunque todavía hay algún error en algunos nombres de elementos. Aquí os dejo las soluciones para los que estén atascados y no puedan dormir por las noches: Sustancia primaria Aire=Elemento primario  Fuego=Elemento primario  Agua=Elemento primario  Tierra=Sustancia Primaria Arena=Piedra + Aire Piedra=Tierra + Fuego Arcilla=Arena + Pantano Caliza=Tierra + Amonitas Carbono=Fuego + Madera Cloro=Fuego + Sal + Electricidad CO2(Dióxido de Carbono)=Ceniza + Ácido nítrico Electricidad=Relámpago+ Metales Gas natural= Yacimiento de gas + Pozo Helio=Refinería de gas + Gas Natural Hidrógeno=Electricidad + Agua Hielo=Frío + Agua Imán=Piedra + Metales Metano=Deshechos Vegetales + Pantano Oxígeno=Electricidad + Agua Petróleo=Unidad

JAXB: Leer y escribir ficheros XML

Muchas veces en nuestras aplicaciones debemos manejar documentos XML ( Extensible Markup Language ). Este lenguaje se ha convertido en un estándar para intercambio de datos entre programas y aplicaciones a través de Internet. En un esquema XML (o  XSD ) podemos definir los elementos que pueden aparecer en un documento XML así como las relaciones entre los mismos. JAXB ( Java Architecture for XML Binding ) es un estándar Java para transformar un esquema XML (o  XSD ) en una representación a objetos java. Mediante la API de JAXB podemos mapear un objeto Java a un documento XML ( "marshall" ) y el proceso contrario, es decir, a partir de un esquema XML crear su conjunto de objeto Java asociado ( "unmarshall" ). JAXB Resumiendo lo que nos proporciona JAXB es: Generación de objetos Java a partir de un XSD a través de un compilador Proporciona capacidades de marshall/unmarshall (escribir fichero XML desde java y al contrario) Integración con Maven a través de xj

Matemáticas y cine.

El otro día estaba viendo por la televisión una película llamada 21 blackjack . En una escena de la película el profesor de matemáticas ( Kevin Spacey ) le presenta a uno de sus alumnos la siguiente situación: se encuentra en un concurso en la que debe escoger entre tres puertas (1,2 y 3). En dos de ellas hay una cabra, sin embargo en una de las 3 hay un flamante coche nuevo. El alumno responde que quiere abrir la puerta. El presentador, conocedor de lo que hay detrás de cada puerta decide abrir otra puerta diferente mostrando detrás de ella una cabra. El profesor se dirige al alumno y le pregunta, ¿cambiarías la puerta o te quedarías con la puerta que tienes? Muchos de nosotros cambiaríamos de puerta pensando que es una treta del presentador para engañarnos. ¿Cual elegiríais vosotros? Al comienzo tenemos 1/3 de probabilidades de acertar la puerta donde está el coche. Una vez que el presentador abre la puerta con una cabra, la mayoría de gente piensa que hay la misma probabilidad de