Sistema de plantillas en menos de 50 líneas

En este post presentaré una solución cómoda y rápida (que no tiene porqué ser la mejor) para crear un sistema de plantillas basado en Java. En primer lugar voy a aclarar a qué quiero referirme cuando hablo de "sistema de plantillas". La idea es la siguiente, partiendo de un texto como el siguiente:
Hola ${usuario}, hoy es ${fecha}

Vamos a diseñar un sistema que reciba este texto (en forma de String o InputStream) y un mapa de propiedades, de forma que sustituya todo lo que encuentre del tipo ${clave} por el valor correspondiente en el mapa.

Editado 24/03/2009: Ver solución mediante la librería commons-lang de Apache
El código al completo sería el siguiente:

package org.tutorialexception.templatemanager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TemplateManager {
public static String template(String template, Map<String, String> map) {
Pattern pattern = Pattern.compile("\\$\\{([^\\}] )\\}");
Matcher matcher = pattern.matcher(template);
StringBuffer stringBuffer = new StringBuffer();
while (matcher.find()) {
String group = matcher.group(1);
matcher.appendReplacement(stringBuffer, map.get(group));
}
matcher.appendTail(stringBuffer);
return stringBuffer.toString();
}

public static String template(InputStream template, Map<String, String> map) {
return template(convertStreamToString(template), map);
}

public static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line   "\n");
}
} catch (IOException e) {  
return "";
} finally {
try {
is.close();
} catch (IOException e) {}
}
return sb.toString();
}
}


Ahora vamos a probar la clase:

package org.tutorialexception.templatemanager;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Main {
public static void main(String[] args) {
String template = "Hola ${usuario}, hoy es ${fecha}";
Map<String, String> map = new HashMap<String, String>();
map.put("usuario", "tutorialException");
map.put("fecha", new Date().toString());
System.out.println(TemplateManager.template(template, map));
}
}


El resultado será parecido al siguiente:

Hola tutorialException, hoy es Thu Mar 19 13:42:44 CET 2009

Editado 24/03/2009: Gracias a Wagner Santos vemos otra forma de hacerlo mucho más fácil, usando la librería commons-lang de Apache, en concreto la clase StrSubstitutor. Podemos descargar la librería de apache de la siguiente URL:
Nuestro ejemplo quedaría ahora de la siguiente forma:
package org.tutorialexception.templatemanager;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.text.StrSubstitutor;

public class Main2 {

public static void main(final java.lang.String[] args) {
String template = "Hola ${usuario}, hoy es ${fecha}";
Map<String, String> map = new HashMap<String, String>();
map.put("usuario", "tutorialException");
map.put("fecha", new Date().toString());
System.out.println(StrSubstitutor.replace(template, map));
}
}

Como vemos, la invocación del método es similar, aunque esta clase nos ofrece muchas más alternativas.
Fuente: http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/StrSubstitutor.html

2 comentarios:

Anónimo dijo...

Muy enfriar! Otra forma de hacerlo es http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/StrSubstitutor.html.

Unknown dijo...

Gracias por el apunte, editada la entrada.

Publicar un comentario