Buenas prácticas con Grails: Crear librerías de etiquetas
domingo 14/06/2009
Para un proyecto en el que acabamos de empezar a trabajar (del que iremos dando más detalles próximamente, porque creo que os interesará a todos vosotros), nos hemos visto con la siguiente necesidad: tenemos que mostrar dentro de una GSP un fragmento de html estático que podrá cambiar con cierta frecuencia (no todos los días, pero sí 4 o 5 veces al año).
Podríamos poner el texto en plantillas GSP, pero cuando una aplicación Grails se está ejecutando en el entorno de producción, las páginas GSP se compilan la primera vez que son requeridas, y se guarda el resultado en memoria con lo que los cambios no se reflejan hasta que reiniciamos el servidor. Es posible desactivar este comportamiento mediante configuración, pero perderíamos más en rendimiento de lo que ganamos en funcionalidad.
Por tanto tenemos dos opciones:
1. Reflejarlo en el modelo de datos, mediante una entidad que represente los distintos fragmentos de html y que podamos gestionar como si fuera un gestor de contenidos. Este enfoque es el que seguimos en goCMS (que hace funcionar este portal), pero necesita mucho código, y nos parecía que no tiene mucho sentido en una aplicación que no es gestor de contenidos como tal.
2. Incluir el html en las GSPs desde un archivo html externo estático. Mediante una etiqueta que podamos incrustar en las GSPs y encapsule la lógica de localizar el archivo, leer su contenido e incluírlo en la respuesta. Este enfoque nos pareció más adecuado para este proyecto particular.
Comparado con las librerías de etiquetas JSP, crear tus propias tags con Grails es enormemente sencillo. Un taglib en Grails es simplemente una clase cuyo nombre termina con TagLib y que se encuentra en la carpeta grails-app/taglib de nuestro proyecto.
Podemos crear el archivo a mano, o utilizar el script grails create-tag-lib, que creará además la batería de tests unitarios. Dentro de una librería de tags, cada etiqueta será una closure que recibe dos argumentos: los atributos que se fijaron al invocarla, y el contenido de la etiqueta. Lo verás más fácilmente con un ejemplo.
Lo primero será crear una aplicación, que llamaremos 'tagsdemo', para hacer nuestras pruebas:
grails create-app tagsdemo
Después, dentro de la carpeta tagsdemo, haríamos:
grails create-tag-lib demo
Supongamos que necestiamos una etiqueta que haga que todo su contenido se muestre con un borde de un color específico. En el archivo generado, grails-app/taglib/DemoTagLib.groovy, escribimos algo así:
class DemoTagLib {
static namespace='demo'
def conBorde = {attrs, body ->
if(!attrs.color) attrs.color = '#f00'
out << "< div style='border:1px solid ${attrs.color}' >"
out << body()
out << "< /div >"
}
Lo primero que vemos es la propiedad estática namespace, que permite organizar nuestras etiquetas. Dentro de nuestras páginas GSP tendremos que invocar los tags de esta librería como ... . Si no fijamos ningún namespace, se usará el nombre por defecto: 'g'.
Lo siguiente es un tag simple con nombre "conBorde", que encierra lo que pongamos dentro con un borde rojo usando un div con estilo CSS. Como ves, utilizamos el objeto implícito out para volcar el html que generamos. La forma de usar este tag sería así:
Esto saldrá dentro de un recuadro gris
Sencillo ¿verdad? Veamos ahora lo que nos interesa: el tag que incrusta el contenido de un archivo estático. Lo que queremos es invocarla desde cualquier GSP así:
de forma que el contenido del archivo /static/demo.html de nuestro proyecto se incruste en el lugar de la llamada. Para implementar la funcionalidad nos aprovecharemos del objeto ServletContext al que tienen acceso tanto los controladores como las GSP y, por supuesto, las etiquetas. Veamos el código para que la etiqueta funcione:
def include = {attrs,body ->
def path = attrs.path
if(!path){
throw new RuntimeException("path attribute not found!")
}
def input = servletContext.getResourceAsStream(path)
if(input){
out << input
}
else{
out << "${path} no encontrado..."
}
}
Como ves es muy sencillo, porque utilizamos el objeto servletContext para acceder al recurso y volcamos el contenido en out. Aquí te dejo el código completo de la librería de etiquetas:
class DemoTagLib {
static namespace='demo'
def conBorde = {attrs, body ->
if(!attrs.color) attrs.color = '#f00'
out << "< div style='border:1px solid ${attrs.color}' >"
out << body()
out << "< /div >"
}
def include = {attrs,body ->
def path = attrs.path
if(!path){
throw new RuntimeException("path attribute not found!")
}
def input = servletContext.getResourceAsStream(path)
if(input){
out << input
}
else{
out << "${path} no encontrado..."
}
}
}
Con esto hemos terminado la etiqueta.
Tienes más información sobre esta y todas las demás funcionalidades de Grails en el libro Manual de desarrollo web con Grails, a la venta en PDF por sólo 10.85€.













Buenas prácticas con Grails: Crear librerías de etiquetas
jaro_ - lunes 15/06/2009
Muchas gracias por compartirlo y por el ejemplo, la verdad es que es muy ilustrativo.
Saludos