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 Pe...

Soluciones Alchemy Classic 442 elementos

Después de la resaca navideña y de la cuesta de enero, volvemos para informar la agradable sorpresa que nos ha dado a los fans de Alchemy Classic la empresa NIASOF ,  tras actualizar el juego Alchemy Classic. Una nueva versión con 442 elementos , interfaz mejorada de grupos y lo más importante, nuevos elementos que descubrir. La gran novedad de esta actualización son los puntos que tienes asignados , con los que puedes  conseguir pistas sobre los elementos que no has abierto todavía como: Conseguir un subelemento de un elemento, con 100 puntos . Conseguir el grupo de un subelemento de un elemento (qué lío , jeje), con 35 puntos . Me gusta, me gusta el enfoque de esta nueva versión aunque los elementos que han sacado me parecen poco originales. Parece que se van agotando las ideas para los elementos nuevos. Aquí van las soluciones: Carbon = Tierra + Turba Sol = Estrella + Tierra Espacio = 3 x Estrella Estrella = Helio + Hidrógeno Oso Pa...

Alchemy Classic

Dentro de los juegos que he descargado con el Android Market hay dos que destacan sobre todos los demás. El primero es Angry Birds (pájaros furiosos), en el cual comandas un ejercito de pájaros para luchar con una piara de cerdos malotes los cuales han robado sus huevos. Básicamente, tienes que ir pasando nivel tras nivel afinando tu puntería lanzando los pájaros a los cerdos que se esconden tras maderas, cristales y piedras. Pero la verdadera joya que no es tan conocida es Alchemy Classic . En este juego puedes desempeñar el papel  de Dios. Comenzando con 4 elementos básicos, Aire, Agua, Tierra y Fuego tienes que ir obteniendo todos los demás elementos de la creación (animales, plantas, herramientas...) mediante la combinación de los 4 primeros. En total hay 238 elementos. Después de una semana y alguna noche sin dormir por fin los he obtenido todos. El último elemento me ha llevado más de la cuenta por su maravillosa traducción. ¿Qué son abrojos? ¿Lo sabéis? Pues no, ...