You are on page 1of 237

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.

0 16 de Diciembre de 2009

Pgina 2

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 3

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

MANUALDE DESARROLLOWEB CONGRAILS


JavaEE,comosiempredebihabersido.

Nacho Brito Calahorro

Pgina 4

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

LICENCIA
Manualde desarrollowebcon Grails se distribuye bajo licencia Creative Commons Reconocimiento-No comercial-Sin obras derivadas 3.0 Espaa. Por tanto, si adquieres una copia del libro tienes derecho a utilizarla bajo las siguientes condiciones:

Debes mantenerel reconocimientoal autor original y mantener todas las referencias existentes tanto a l como a ImaginaWorks Software Factory. No puedesdistribuirla obracomercialmente . Esto significa que no puedes venderla sin consentimiento por escrito del autor original, ni tampoco distribuirla como valor aadido a un servicio de ningn tipo, por ejemplo, si eres formador y utilizas este manual como apoyo a tu curso. Para usos comerciales del libro debes ponerte en contacto con ImaginaWorks en la direccin info@imaginaworks.com o en el telfono 902 546 336. No puedesdistribuirversionesalteradasde la obra. Puesto que el autor asume totalmente la autora de la obra, y es el nico responsable por sus contenidos, l es el nico autorizado a realizar modificaciones o, en su caso, autorizar por escrito a terceros para realizarlas en su nombre.

Salvando estos puntos, que esperamos consideres razonables, la licencia de distribucin de la obra mantiene el resto de tus libertades como propietario de la copia que has adquirido para reproducirla (imprimir todas las copias que necesites, copiar el PDF tantas veces como te haga falta, etc), ensearla o regalrsela a compaeros o amigos, utilizarla en grupos de desarrollo, etc. EL CONTENIDO DE ESTE LIBRO SE PROPORCIONA SIN NINGUNA GARANTA. AUNQUE EL AUTOR HA PUESTO EL MXIMO DE SU PARTE PARA ASEGURAR LA VERACIDAD Y CORRECCIN DE LOS MATERIALES EXPUESTOS, NI L NI IMAGINAWORKS SOFTWARE FACTORY S.L.U. ASUMEN NINGUNA RESPONSABILIDAD POR DAOS O PERJUICIOS CAUSADOS DIRECTA O INDIRECTAMENTE POR LA INFORMACIN CONTENIDA EN ESTE LIBRO.
A lo largo del texto se usarn marcas comerciales pertenecientes a personas y organizaciones, y puede que se omita el smbolo por claridad. No obstante, reconocemos todos los derechos legtimos de los propietarios de las marcas y no tenemos intencin de infringirlos. Java y todas las marcas derivadas son propiedad de Sun Microsistems Inc. Tanto en Estados Unidos como en otros pases. ImaginaWorks Software Factory no mantiene ninguna relacin de afiliacin con Sun Microsistems, ni ha solicitado su aprobacin para la publicacin de este libro.

Copyright 2009 Nacho Brito


ISBN: 978-84-613-2651

Pgina 5

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

PRLOGO
El paisaje de la industria de Java est cambiando. La competitividad de los mercados est impulsando la necesidad de que el desarrollo de software sea ms rpido y gil. Surgen metodologas que promueven estos principios y se producen cambios en los frameworks. Ya no se considera aceptable pasar aos desarrollando un proyecto de software. Los clientes necesitan soluciones y las necesitan ahora. Grails es un nuevo framework web para la plataforma Java que se basa en el lenguaje dinmico Groovy. Mediante el uso de Lenguajes de Dominio Especfico (DSLs) potentes pero a la vez sencillos, la versatilidad de Groovy, y un ecosistema de PlugIns que mejora la productividad en un conjunto cada vez ms amplio de escenarios, Grails se ha hecho inmensamente popular, y un motor de cambio en el espacio Java. Grails permite crear aplicaciones en das, en lugar de semanas. En comparacin con el tpico framework de Java, con Grails se necesita menos cdigo para obtener el mismo resultado. Menos cdigo significa menos errores y menos lneas de cdigo de mantener. Gracias a la estrecha integracin con Java, Grails ofrece un camino de migracin desde entornos Java menos productivos. Grails se puede desplegar en tu servidor de aplicaciones, monitorizar y depurar con tus herramientas y construir con las herramientas de construccin con las que ya ests familiarizado, como Ant y Maven. Participar en el desarrollo de Grails desde el principio me ha dado el privilegio de presenciar el crecimiento de la comunidad. Desde muy al principio, hay un fuerte inters de la comunidad internacional y gracias al soporte de internacionalizacin (i18n) de Grails , hay una forma sencilla de desarrollar aplicaciones multi-idioma. Nacho y sus colegas en ImaginaWorks han sido uno de los motores de la popularizacin de Grails en la comunidad de habla hispana y su dedicacin a mantener el muy popular sitio groovy.org.es ha dado lugar a una gran riqueza de contenidos en espaol. El hecho de que mi mujer tenga origen espaol hace que signifique mucho para m a nivel personal ver cmo Grails florece en esta comunidad en particular. Nacho ha creado un fantstico recurso para los que buscan iniciarse con Grails y obtener resultados productivos rpidamente. Bienvenidos a una nueva era de desarrollo Web en la plataforma Java. Happy coding!

GraemeRocher Grails Project Lead Jefe de Desarrollo Grails en SpringSource


Pgina 6

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 7

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Sobreel autor
NachoBrito (Madrid,1977) - perfil en LinkedIn - lleva ms de 10 aos desarrollando software y formando desarrolladores. Se especializ en la plataforma Java a principios de 2000 y desde entonces ha trabajado en proyectos de todos los tamaos para organismos pblicos y privados. Cuando en 2006 comenz a probar las primeras versiones de Grails, enseguida reconoci el enorme impacto que una herramienta as podra tener en la productividad de los equipos de desarrollo Java. Incorpor la tecnologa al abanico de herramientas de ImaginaWorksy fund groovy.org.es, el primer portal sobre Groovy y Grails en espaol, para el que tuvo la oportunidad de entrevistar a los principales impulsores de ambos proyecto: Graeme Rocher y Gillaume Laforge. Tambin es responsable de otros proyectos relacionados con Groovy, como el sitio web AllAboutGroovy.com. Actualmente desarrolla su carrera profesional en ImaginaWorks Software Factory, compaa que fund en Junio de 2006 y que presta servicios de desarrollo de software a medida, formacin y asesoramiento tecnolgico. En 2009 Nacho cofunda el proyecto Escuela de Groovy, una compaa dedicada exclusivamente a prestar servicios de formacin, asesoramiento y desarrollo a empresas interesadas en adoptar Groovy y Grails como plataforma para desarrollo de aplicaciones JavaEE. Puedes contactar con Nacho en la direccin nacho@escueladegroovy.com

Pgina 8

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Agradecimientos
Si tuviera que dar una respuesta rpida a por qu existe este libro, lgicamente dira que este libro existe porque existe Grails. Por eso el primer agradecimiento debe ir para todo el equipo de desarrollo del framework con GraemeRocher a la cabeza. Pero si me dejasen ms tiempo para pensar mi respuesta, incluira adems Guillaume Lafforgey todo el equipo de desarrollo de Groovy, que estn haciendo una inmensa labor por abrirnos la mente a todos los desarrolladores que vivimos en la mquina virtual Java. Luego tendra que decir que este libro existe porque existe el software libre, porque somos muchos los que pensamos que se llega ms lejos con modelos cooperativos que competitivos, y que para vivir del software no es necesario vendar los ojos de nuestros clientes y encerrarnos para que nadie vea cmo trabajamos. Este libro existe tambin gracias a javaHispano, asociacin con la que colaboro desde hace muchos aos y que siempre ha estado dispuesta a hacer ms accesible el conocimiento. La idea de escribir este manual surgi durante una serie de seminarios gratuitos de introduccin a Groovy y Grails que ImaginaWorks y javaHispano han organizado a lo largo de 2009. Y dejo para el final lo ms importante. Este libro existe porque he tenido la ilusin, la fuerza y las ganas de escribirlo, y no tendra nada de eso si no fuera por mi familia, por mi mujer, Ana, por mis hijas Clara y Emma a las que tantas horas robo al da para teclear y teclear. Este libro existe porque mis padres me educaron y sirvieron de ejemplo en la constancia, el trabajo duro y el compromiso con uno mismo. Va por todos ellos.

PD. Esta segunda edicin del Manual existe gracias a todos los que creyeron que mereca la pena invertir su dinero en la versin 1.0. De no haber sido por el xito de aquella no hubiera tenido sentido seguir con la 1.1. Mi agradecimiento tambin para todos aquellos pioneros :-)

Pgina 9

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 10

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 11

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ndice de Contenidos
LICENCIA........................................................................................................................ 5 PRLOGO....................................................................................................................... 6 Sobre el autor.................................................................................................................. 7 Agradecimientos.............................................................................................................. 8 1. Introduccin......................................................................................................................... 19 La bsqueda.................................................................................................................. 20 La solucin..................................................................................................................... 20 El libro............................................................................................................................ 21 2. Cmo usar este manual...................................................................................................... 24 Requisitos previos......................................................................................................... 26 3. Gua rpida......................................................................................................................... 28 Convencin mejor que configuracin........................................................................ 29 DRY: Don't repeat yourself! ("'No te repitas!")......................................................... 29 Instalar Grails................................................................................................................. 30 Estructura de una aplicacin Grails............................................................................... 30 Definicin del Modelo de Datos..................................................................................... 31 Scaffolding..................................................................................................................... 34 Cundo usar el Scaffolding.................................................................................. 36 Configuracin de acceso a datos.................................................................................. 36 Controladores................................................................................................................ 37
Pgina 12

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Vistas: Groovy Server Pages......................................................................................... 37 Helpers para AJAX.................................................................................................... 38 Custom tags.............................................................................................................. 38 Servicios........................................................................................................................ 39 Desplegar nuestra aplicacin........................................................................................ 40 4. Lo que debes saber antes de empezar.............................................................................. 41 Metodologas................................................................................................................. 42 El patrn Model View Controller.................................................................................... 42 Inversin de Control (IoC).............................................................................................. 44 5. Anatoma de Grails: La lnea de comandos........................................................................ 45 Personalizar la generacin de cdigo............................................................................ 49 6. Configuracin...................................................................................................................... 51 El archivo Config.groovy................................................................................................ 52 Configuracin de log4j.............................................................................................. 53 Configuracin de GORM........................................................................................... 54 El archivo DataSource.groovy....................................................................................... 54 El archivo BuildConfig.groovy........................................................................................ 55 Configuracin de depencencias................................................................................ 56 7. El modelo de datos: GORM................................................................................................ 58 Crear entidades............................................................................................................. 59 Validaciones.............................................................................................................. 60 Sobre los mensajes de error................................................................................ 62 Cmo mapear asociaciones...................................................................................... 63
Pgina 13

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Relaciones Uno-A-Uno......................................................................................... 63 Relaciones Tiene-Un............................................................................................ 64 Relaciones Uno-A-Muchos................................................................................... 64 Relaciones Muchos-a-Muchos............................................................................. 66 Como mapear composiciones....................................................................................... 66 Cmo mapear herencia................................................................................................. 67 Utilizar esquemas de datos heredados......................................................................... 68 Operaciones sobre el modelo de datos......................................................................... 70 Actualizaciones......................................................................................................... 70 Bloqueos de datos................................................................................................ 71 Consultas.................................................................................................................. 71 Dynamic Finders................................................................................................... 72 Criteria.................................................................................................................. 74 Named Queries.................................................................................................... 74 Hibernate HQL...................................................................................................... 75 Conceptos avanzados de GORM.................................................................................. 75 Eventos de persistencia............................................................................................ 75 Poltica de cach....................................................................................................... 76 Sobre las cachs de objetos................................................................................ 76 Configurando Hibernate....................................................................................... 77 Definir la poltica de cach en cada clase............................................................ 78 Usar las cachs fuera de GORM......................................................................... 78 8. Controladores...................................................................................................................... 80
Pgina 14

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

mbitos.......................................................................................................................... 83 El mtodo render, a fondo............................................................................................. 84 Encadenar acciones...................................................................................................... 86 Interceptors.................................................................................................................... 87 Procesar datos de entrada............................................................................................ 88 Data Binding.............................................................................................................. 88 Recibir ficheros......................................................................................................... 89 Evitar el doble post.................................................................................................... 91 Objetos Command.................................................................................................... 92 9. Servicios.............................................................................................................................. 94 Por qu deberan importarte los servicios..................................................................... 95 Ok, pero qu es un Servicio en GRAILS?................................................................... 96 Poltica de creacin de instancias............................................................................. 97 Mtodos transaccionales.......................................................................................... 98 10. Vistas: Groovy Server Pages.......................................................................................... 100 Etiquetas GSP............................................................................................................. 102 Etiquetas para manejo de variables........................................................................ 102 Etiquetas lgicas y de iteracin............................................................................... 103 Etiquetas para filtrar colecciones............................................................................ 103 Etiquetas para enlazar pginas y recursos............................................................. 104 Etiquetas para formularios...................................................................................... 104 Etiquetas para AJAX............................................................................................... 105 Eventos Javascript............................................................................................. 106
Pgina 15

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Generar XML o JSON en el servidor.................................................................. 108 Usar las etiquetas como mtodos........................................................................... 109 Crear TagLibs.............................................................................................................. 109 Utilizar libreras de etiquetas JSP................................................................................ 110 Layouts: Sitemesh....................................................................................................... 111 Cmo seleccionar el layout para una vista............................................................. 112 11. Definiendo la estructura de URLs de nuestra aplicacin................................................ 114 Cmo afecta UrlMappings a la etiqueta link............................................................ 117 Capturar cdigos de error............................................................................................ 117 Capturar mtodos HTTP.............................................................................................. 118 Patrones de URLs con nombre............................................................................... 118 12. Web Flows...................................................................................................................... 120 13. Filtros.............................................................................................................................. 124 Ejemplo: filtro XSS....................................................................................................... 126 14. Bateras de pruebas........................................................................................................ 128 Tests unitarios............................................................................................................. 131 Los mtodos mock.................................................................................................. 133 Tests de integracin.................................................................................................... 134 Tests funcionales......................................................................................................... 138 15. Internacionalizacin........................................................................................................ 141 Cmo maneja Grails la i18n........................................................................................ 142 Cmo mostrar mensajes en el idioma correcto........................................................... 143 Generar scaffolding internacionalizado....................................................................... 143
Pgina 16

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

16. Seguridad........................................................................................................................ 147 Tipos de ataques......................................................................................................... 148 Inyeccin de SQL.................................................................................................... 148 Denegacin de servicio........................................................................................... 149 Inyeccin de HTML/Javascript................................................................................ 150 Codecs......................................................................................................................... 151 17. Desarrollo de Plugins...................................................................................................... 152 Qu podemos hacer en un plugin?........................................................................... 154 Tu primer plugin: aadir artefactos a la aplicacin...................................................... 155 Distribuir el plugin.................................................................................................... 158 Qu ocurre cuando instalamos un plugin en una aplicacin?.............................. 159 Tu segundo plugin: aadir mtodos dinmicos a las clases de la aplicacin.............160 18. Servicios web con Grails: SOAP vs REST .................................................................... 163 Usando SOAP............................................................................................................. 164 Usando XFire.......................................................................................................... 164 Usando REST.............................................................................................................. 165 Clientes REST para pruebas.................................................................................. 166 Usando Poster.................................................................................................... 167 Usando rest-client............................................................................................... 168 Implementando el servicio...................................................................................... 169 Procesar peticiones POST................................................................................. 169 Procesar peticiones GET.................................................................................... 171 Procesar peticiones PUT.................................................................................... 172
Pgina 17

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Procesar peticiones DELETE............................................................................. 173 Servicios REST compatibles con JAX-RS.............................................................. 174 19. Entornos de desarrollo.................................................................................................... 177 Entornos Integrados.................................................................................................... 179 Netbeans (Gratuito)................................................................................................. 179 SpringSource Tool Suite (Basado en eclipse, Gratuito)......................................... 183 IntelliJIDEA (205).................................................................................................. 188 Editores de Texto......................................................................................................... 189 UltraEdit (49,95).................................................................................................... 189 TextMate (48,75)................................................................................................... 190 E Text Editor (34,95)............................................................................................. 190 APNDICE A. Introduccin a Groovy .................................................................................. 192 El papel de Groovy en el ecosistema Java.................................................................. 193 Descripcin rpida del lenguaje................................................................................... 193 Qu pinta tiene el cdigo Groovy? ......................................................................... 194 Declaracin de clases............................................................................................. 195 Scripts..................................................................................................................... 195 GroovyBeans.......................................................................................................... 196 Cadenas de texto, expresiones regulares y nmeros............................................. 196 Listas, mapas y rangos........................................................................................... 197 Closures.................................................................................................................. 198 Estructuras de control............................................................................................. 199 Posibilidades de integracin con libreras Java existentes ........................................ 200
Pgina 18

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Ejemplos de la vida real:.............................................................................................. 200 Trabajar con XML.................................................................................................... 200 Trabajar con SQL.................................................................................................... 201 Trabajar con Ficheros............................................................................................. 202 Servicios web.......................................................................................................... 203 ImaginaWorks, miembro fundador de Escuela de Groovy...................................................206 Control de versiones............................................................................................................. 207

Pgina 19

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

1. Introduccin

Pgina 20

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Hola, bienvenido a manualde desarrollowebcon Grails. El objetivo de este libro es presentarte los conceptos fundamentales que se encuentran detrs de esta plataforma para desarrollo de aplicaciones web con Groovy y Java, y darte algunas ideas sobre la mejor forma de aplicarlos.

La bsqueda
Nuestra experiencia con Grails comienza a finales de 2006, cuando buscbamos herramientas que optimizaran nuestro proceso de desarrollo con JavaEE. Somos un equipo pequeo de desarrolladores, y no podamos permitirnos el tiempo que haba que perder cada vez que comenzbamos un nuevo proyecto en configurar el entorno de desarrollo, pruebas y preproduccin, por no hablar de la cantidad de horas dedicadas a escribir y mantener XML. Entonces se empezaba a hablar con fuerza de frameworks como Rubyon Rails o Django, de las ventajas de usar Conventionover Configuration (emplear convenciones para definir el tipo y las caractersticas de los artefactos, en lugar de hacerlo en archivos de configuracin) y de las virtudes de los lenguajesdinmicospara crear aplicaciones con menos cdigo de fontanera. Los lenguajes dinmicos, entre otras cosas, evitan la necesidad de especificar el tipo de dato de una variable en el momento de declararla en el cdigo fuente, sino que el entorno de ejecucin es capaz de determinarlo en tiempode ejecucina partir de los datos que almacenemos en ella. Esta idea, simple inicialmente, alcanza su mxima expresin cuando hablamos de lenguajes dinmicos orientados a objetos, ya que nos permiten, por ejemplo, definir clases en tiempo de ejecucin para que los objetos se ajusten a un esquema que no puede conocerse de antemano, o aadir propiedades y mtodos a un objeto para que haga ms cosas de aquellas para las que fue inicialmente concebido. Sonaba muy bien, pero cuando le dedicbamos a estos frameworks nuestra pruebade los 20 minutos terminbamos echando de menos la plataforma Java. La sensacin era que, efectivamente, podamos hacer un prototipo de nuestra aplicacin en unos minutos, pero... con qu reemplazbamos las libreras de Jakarta Commons? y Quartz? y Compass/Lucene? e iText? y JPA/JDO? y JasperReports? y JUnit? Eran demasiadas herramientas a las que tenamos que renunciar para adoptar estos nuevos entornos, y eso haca que no mereciese la pena el cambio. An as estbamos en la senda que nos llevara a encontrar lo que estbamos buscando.

Pgina 21

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

La solucin
Habamos aprendido el valor de los lenguajes dinmicos, y sabamos que haba algunos que podan usarse en la mquina virtual, como Ruby (Jruby), JavaScript (Rhino), Python (Jython), Y as llegamos a Groovy(http://groovy.codehaus.org/), un lenguaje dinmico desarrollado desde y para Java. Lo que ms nos atrajo del lenguaje es que podamos empezar a escribir clases Groovy como si fueran Java, ya que la sintaxis es altamente compatible, y poco a poco ir aprovechando las maravillas sintcticas a medida que lo descubrisemos. Adems, la compatibilidad con todo nuestro cdigo heredado y las libreras que conocamos era total (Groovy es Java), de forma que podamos reutilizar lo que ya tenamos y aadir a nuestro cajn de herramientas cosas como sobrecarga de operadores, programacin dinmica, closures, y mucho ms. El salto de Groovy a Grails fue inmediato. Grails es, con toda seguridad, el proyecto ms emblemtico construido con Groovy. Se trata de un framework para desarrollo web que se parece mucho a Rails por fuera (incluso en el nombre, que originalmente era Groovyon Rails y tuvo que ser cambiado a peticin de la gente de RoR), pero que por dentro est construido sobre una base slida formada por proyectos como Spring container , Hibernate , SiteMesh , Log4J y un largo etctera formado por plugins que permiten incorporar Quartz, Compass/Lucene, JasperReports, ... Segn cuenta Graeme Rocher en The definitive guide to Grails (Apress, ISBN 159059-758-3): El objetivode Grails era ir msall de lo que otros lenguajesy sus frameworksasociadospodan ofreceren el espaciode las aplicacionesweb. Grails se proponahacerlo siguiente: Integrarseestrechamentecon la plataformaJava. Ser sencillo en la superficie, pero mantenerla flexibilidadpara accedera los potentesframeworks Javasobrelos que se construa. Aprenderde los errorescometidosen la ya maduraplataformaJava. El uso de Groovycomopuntode partidapara el frameworkle proporcionuna enormeventajainicial. El objetivode Groovyera crear un lenguajecon que permitiesea programadoresJavauna fcil transicinal mundode los lenguajesde script con tipadodinmico,proporcionandofuncionalidadesimposiblesde implementarcon lenguajesde tipadoesttico. Enseguida nos dimos cuenta del potencial de la tecnologa, y de cmo poda suponer una revolucin en la manera de desarrollar aplicaciones para la plataforma JavaEE, no slo porque inclua las palabras mgicas "conventionover configuration" , "Scaffolding" y "Don't repeat yourself", sino porque traa esos conceptos a la JVM de una forma completamente transparentey compatible con todo el cdigo Java existente. Por fin exista una tecnologa que encajaba con las metodologas giles y que no nos obligaba a abandonar la plataforma Java ni nuestro Know-How acumulado.

Pgina 22

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El libro
Desde entonces, en ImaginaWorkshemos trabajado con Groovy y Grails profundizando en las ideas que proponen y divulgando sus ventajas (fundamos el portal http://groovy.org.es) . Hemos desarrollado sitios web con Grails de todos los tamaos, sitios que a da de hoy estn en produccin y que realizan labores desde el ms bsico gestor de contenidos, hasta los sitios MiddleWare con servicios web SOAP y REST, pasando por plataformas B2B y sitios WAP. Tambin impartimos formacin a instituciones pblicas y privadas, y prestamos servicios de consultora y direccin de proyectos a empresas de desarrollo que se inician en el uso de Groovy y Grails. Este manual incluye todo lo que hemos aprendido durante el tiempo que hemos trabajado con Grails. Incluye una referencia (no exhaustiva) de las funcionalidades principales del framework, pero lo ms valioso es que incluye las lecciones que nos han aportado estos tres aos de experiencia y que te ahorrarn mucho tiempo y quebraderos de cabeza. Respecto al formato, hemos querido que este sea un libro digital por dos razones: La primera, parano tenerintermediarios . Al editar nosotros mismos el libro (bajo la marca Ediciones giles) podemos elegir cundo lo publicamos, cmo y por cunto lo vendemos, y sobre todo, podemos publicar nuevas revisiones a cuando sea necesario para corregir erratas, adaptar el contenido a nuevas versiones de Grails o aadir captulos nuevos. La segunda, pararespetartu libertad . Ya que t has comprado esta copia del libro, te corresponden ciertas libertades que queremos respetar. Puedes decidir si lo lees en la pantalla o en papel, imprimir tantas copias como necesites, enviar el archivo PDF por email a tus amigos o compaeros, puedes llevarla al trabajo en un lpiz de memoria usb... Tienes ms detalles sobre los trminos de uso en el APNDICE B. Esperamos que compartas nuestra visin de este proyecto, y que el manual te gue en el aprendizaje de Grails y te permita sacar lo mejor de ti mismo en tus proyectos.

Madrid, Mayo de 2009 ImaginaWorks Software Factory

Pgina 23

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 24

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

2. Cmo usar

st

manua!

Pgina 25

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El objetivo de este libro es orientar a quienes empiezan en el desarrollo con Grails, aportando datos suficientes sobre la tecnologa y consejos para aplicarla de la mejor forma segn el caso. Pero para cumplir con esa tarea es necesario que este libro sea una obragil, en el sentido en que usamos esa palabra en desarrollo de software. Necesitamos que la obra evolucione a la par que las tecnologas que trata, y que las aportaciones de los lectores se reflejen con la mayor frecuencia que sea posible, para no quedar obsoleta y perder su utilidad. Por eso se trata de un libro vivo, que coexiste con un sitio web en el que puedes (y te animo a hacerlo) compartir tus experiencias, comentarios, dudas y correcciones sobre el texto: http://www.manual-de-grails.es

Con todas las aportaciones y correcciones intentar publicar revisiones del texto con frecuencia, y recoger los cambios y novedades que aporten futuras versiones de Grails. El libro est dividido en 18 captulos y un Anexo: El captulo3 es una gua rpida que puedes usar para tener una impresin general a vista de pjaro acerca de Grails. Te permitir realizar un primer proyecto y familiarizarte con la estructura de una aplicacin web MVC. En los captulos siguientes iremos recorriendo cada uno de los aspectos fundamentales del entorno con mayor detenimiento. El captulo4 presenta los principios tericos en los que se basa Grails, patrones y convenciones que te ser muy til comprender antes de empezar a profundizar en los aspectos tcnicos. El captulo5 hace un recorrido por todos los scripts que forman parte de Grails, y que podemos lanzar desde la lnea de comandos (o utilizando el IDE que prefieras, con el plugin correspondiente) para activar la magia . A partir de este punto comienza el repaso por todas las tcnicas que necesitas conocer para desarrollar aplicaciones El captulo6 te ensea a configurar tu aplicacin Grails para personalizar aspectos como las trazas, el acceso a bases de datos, el negociado de tipos mime con el navegador, etc. Los captulos7, 8, 9 y 10 recorren el ncleo duro de cualquier aplicacin MVC: el modelo de datos, la capa de control, la capa de servicios y la capa de presentacin. El captulo11 te ensea todo lo necesario para definir el esquema de URLs de tu aplicacin, si no ests satisfecho con el usado por defecto. El captulo12 describe el uso de WebFlows , una tcnica que permite definir
Pgina 26

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

conversaciones que se extienden ms all de una peticin HTTP, al estilo de los asistentes en las aplicaciones de escritorio. El captulo13 introduce el concepto de Filtro, que puedes usar para implementar cuestiones transversales de tu aplicacin, como la seguridad o la monitorizacin. El captulo14 te sumerge de lleno en las facilidades de Grails para realizar pruebas unitarias, de integracin y funcionales sobre tus proyectos, y explica por qu deberas prestar atencin a este aspecto. El captulo15 explica cmo funciona la internacionalizacin de aplicaciones con Grails. El captulo16 habla sobre seguridad, en trminos generales de web, y especficos de Grails. El captulo17 te introduce en el desarrollo de plugins, y te explica los beneficios de desarrollar aplicaciones modulares. El captulo18 abarca todo lo relacionado con servicios web y Grails, y realiza una comparacin entre los paradigmas ms utilizados hoy en da: REST y SOAP. El captulo19 realiza un breve repaso por el soporte para Grails en los editores de texto y entornos de desarrollo ms populares. Al final del texto encontrars un apndicesobreGroovyque te recomiendo leas detenidamente para familiarizarte con el lenguaje. A fin de cuentas, la mayor parte del cdigo que escribas en Grails ser Groovy y es muy importante que conozcas su sintaxis y herramientas bsicas.

Requisitosprevios
Aunque no es necesario, aprovechars mejor el contenido de este libro si tienes alguna experiencia desarrollando aplicaciones web con JavaEE. Todos los conocimientos que poseas sobre Servlets y JSPs, servidores de aplicaciones y bases de datos te sern de gran utilidad para asimilar mejor los conceptos de Grails. Adems, si ests familiarizado con Spring (http://www.springsource.org/about) e Hibernate (https://www.hibernate.org/) podrs sacar ms provecho a las funcionalidades avanzadas de ambos. Para una documentacin exhaustiva de todas las funcionalidades de Grails te recomiendo la gua oficial: http://grails.org/doc/1.2,x/ Si no tienes experiencia en JavaEE no te preocupes, an as podrs aprender a desarrollar aplicaciones web con Grails de forma sencilla con este manual, e investigar ms tarde las ventajas de incorporar mdulos y libreras escritas en Java a tus proyectos.

Pgina 27

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 28

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

3. "u#a r$ida.

Pgina 29

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

"rai!s

:i)r r#as +a;a%cri$t4 <o-o7 Protot=$ 7 >,I7 ...

P!ugins 1ram 2or34 5uart67 *c gi7 Com$ass7 8! 97 ...

"/0&

"%P

"roo;=
%it & s' +.. %$ring !og4+,nit (i) rnat *nt

+a;a
Grails es un framework para desarrollo de aplicaciones web construido sobre cinco fuertes pilares:

Groovypara la creacin de propiedades y mtodos dinmicos en los objetos de la aplicacin. Spring para los flujos de trabajo e inyeccin de dependencias. Hibernatepara la persistencia. SiteMeshpara la composicin de la vista. Ant para la gestin del proceso de desarrollo.

Desde el punto de vista del diseo, Grails se basa en dos principios fundamentales:

Convencinmejorqueconfiguracin
Aunque en una aplicacin Grails existen archivos de configuracin, es muy poco probable que tengas que editarlos manualmente ya que el sistema se basa en convenciones. Por ejemplo, todas las clases de la carpeta grails-app/controllers sern tratados como Controladores, y se mapearn convenientemente a las urls de tu aplicacin.

DRY:Don't repeatyourself! ("'Note repitas!")


La participacin de Spring Container en Grails permite inyeccin de dependencias mediante IoC (Inversion of Control), de forma que cada actor en la aplicacin debe definirse una nica vez, hacindose visible a todos los dems de forma automtica.
Pgina 30

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

InstalarGrails
Para empezar a trabajar tenemos que instalar el entorno. Lo primero ser descargar Grails desde la web del proyecto: http://www.grails.org/Download descomprimimos el archivo en la carpeta que elijamos y fijamos la variable $GRAILS_HOMEpara que apunte a esa carpeta. Si estamos en linux, tambin tendremos que dar permisos de ejecucin a todo lo que est en $GRAILS_HOME/biny $GRAILS_HOME/ant/bin. Para comprobar si todo ha ido bien, podemos escribir en una consola el comando grails help , que nos mostrar un mensaje con la versin del entorno que estamos ejecutando y los scripts que podemos invocar.

Estructurade una aplicacinGrails


Grails contiene todo lo necesario para desarrollar desde el primer momento, no necesitamos servidor adicional ni base de datos (aunque lgicamente podemos usar los que tengamos instalados, sobre todo en produccin). Para comenzar una aplicacin Grails nos colocamos en la carpeta donde deseemos tener el proyecto, y escribimos: $ grails create-app test Cuando el proceso termina, tenemos una carpeta de nombre "test" (o el nombre que le hayamos dado a nuestra aplicacin), con la siguiente estructura: + grails-app + conf ---> Archivos de configuracin + hibernate ---> Config. hibernate (opcional) + spring ---> Config. spring + controllers ---> Controladores + domain ---> Entidades + i !n ---> message bundles + services ---> "ervicios + taglib ---> #ibrer$as de eti%uetas + utils ---> Clases de utilidad + vie&s ---> 'istas + la(outs ---> #a(outs "ite)esh + lib + scripts + src + groov( ---> *tras clases +roov( + ,ava ---> *tras clases -ava + test ---> Casos de prueba + &eb-app ---> .a$/ de mi aplicacin &eb. Las carpetas donde pasaremos la mayor parte del tiempo son grails-app, que contiene

Pgina 31

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

todos los artefactos que el entorno ir generando y que tendremos que modificar para adaptar su funcionamiento a nuestra aplicacin, y webapp, que contiene la estructura de nuestra aplicacin web. En particular, web-app/csscontiene la/s hoja/s de estilo y webapp/imagesel contenido grfico. Si trabajas con Netbeans, ten en cuenta que el IDE te mostrar distintas vistas de tu proyecto. En la pestaa Files vers la estructura real de la aplicacin, mientras que en la pestaa Projects vers los artefactos agrupados por familias lgicas:

Pgina 32

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Si ejecutamos el comando grails run-app podremos ver el aspecto de nuestra aplicacin (bastante vaco de momento):

Definicindel Modelode Datos


Vamos a tratar ahora las cuestiones relacionadas con el modelo de datos y las relaciones. Para ello vamos a construir un pequeo sitio web que permita a los usuarios compartir trucos y fragmentos de cdigo Groovy, al estilo JavaAlmanac . Empezamos por definir nuestro modelo: el sitio tratar con trucos publicados por los usuarios. Tambin ser posible publicar comentarios a un truco, as como valorar su calidad para controlar la utilidad de la informacin. Si un truco es denunciado por otro usuario, se retirar provisionalmente y se avisar a su autor para que lo revise. As que una primera aproximacin podra ser esta:

Pgina 33

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

0suario nombre12e3to fecha14echa email12e3to perfil12e3to 2ruco autor10suario comentarios1#ista denunciado15oolean te3to12e3to titulo12e3to fecha14echa Comentario autor12e3to te3to12e3to fecha14echa Para empezar, como ya hemos hecho antes, seleccionamos la carpeta donde vamos a trabajar y ejecutamos el comando $ grails create-app +roov(Almanac Entramos en el directorio GroovyAlmanac, y creamos nuestras clases del dominio: $grails create-domain-class usuario $grails create-domain-class truco $grails create-domain-class comentario Una vez creados los archivos, los editamos para completar las entidades: grails-app/domain/Usuario.groovy: class 0suario 6 static has)an( 7 8trucos12ruco9 "tring nombre "tring email :ate fechaAlta ; grails-app/domain/Comentario.groovy: class Comentario 6 static belongs2o 7 2ruco "tring autor "tring te3to :ate fecha ; grails-app/domain/Truco.groovy: class 2ruco 6 static has)an( 7 8comentarios1Comentario9 static belongs2o 7 0suario #ist comentarios
Pgina 34

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; Aparte de que no necesitamos definir getters ni setters (porque nuestras clases son GroovyBeans, tienes ms informacin sobre esto en el APNDICEA), estas entidades tienen otra particularidad: Comentario define una variable esttica belongs2o que indica la parte "N" de una relacin 1:N entre Truco y Comentario, mientras que esta ltima define una propiedad esttica de nombre has)an( que representa el lado "1" (un Map, con cadenas de texto como claves y clases como valores). Con ellas estamos indicando a grails debe mapear esta relacin a la base de datos. Como ves hemos definido la propiedad comentarios explcitamente, mientras que en Comentario no hay ninguna propiedad truco. En realidad podramos haber omitido comentarios, pero entonces grails usara la coleccin por defecto, que es Set, y queremos que los comentarios guarden el orden en que son aadidos a la coleccin, as que forzamos el uso de un List. Igualmente, hay una relacin 1:N entre los trucos y los usuarios (un usuario puede publicar varios trucos, cada truco pertenece a un usuario). Para controlar la validacin de las propiedades podemos definir restricciones mediante la palabra reservada constraints: class 0suario 6 static has)an( 7 8trucos12ruco9 "tring nombre :ate fechaAlta "tring email static constraints 7 6 nombre(si/e1<..=>) email(email1true) ; ; class Comentario 6 static belongs2o 7 2ruco "tring autor "tring te3to :ate fecha static constraints 7 6 autor(si/e1<..=>) te3to(ma3"i/e1??????) ; ; class 2ruco 6 static has)an( 7 8comentarios1Comentario9
Pgina 35

:ate fecha "tring titulo "tring te3to boolean denunciado

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

static belongs2o 7 0suario #ist comentarios :ate fecha "tring titulo "tring te3to boolean denunciado static constraints 7 6 titulo(si/e1 >.. >>>) te3to(ma3"i/e1??????) ;

; Probablemente no hace falta explicar mucho lo que significa cada restriccin, es lo bueno de Groovy: el cdigo lo dice casi todo. En las propiedades de tipo texto estamos restringiendo las longitudes mnima y mxima, y en la propiedad que representa un email utilizamos una restriccin incorporada que valida que la cadena de texto cumpla con las restricciones de una direccin de correo electrnico.

Scaffolding
Una vez creado el modelo de datos, podemos solicitar a Grails que genere el controlador y las vistas necesarias para realizar operaciones CRUD con estas entidades: $ grails generate-all comentario $ grails generate-all truco $ grails generate-all usuario Esta tcnica se denomina scaffolding , y genera controladores y vistas a partir de un modelo de datos. Al ejecutar este comando, Grails generar para cada entidad las acciones list, show,edit, delete, create, savey update , a las que podremos acceder desde urls como estas: @8Aplicacin9@8Entidad9@8Accin9 por ejemplo: http1@@localhost1!>!>@+roov(Almanac@truco@list Si vuelves a ejecutar la aplicacin vers que la pgina principal es diferente. Ahora muestra enlaces a los tres controladores principales, y al pulsar sobre cada uno podrs navegar por las acciones de gestin de entidades:
CRUD es un acrnimo para las operaciones bsicas de Creacin, Lectura (Read), Actualizacin (Update) y Borrado (Delete).

Pgina 36

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 37

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El scaffolding crea un esqueleto completo para empezar a trabajar en nuestra aplicacin:

Pgina 38

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Cundousar el Scaffolding
Como ves, el scaffolding es una tcnica muy potente que nos evita construir una porcin importante de nuestra aplicacin. Sin embargo, como todo, tiene sus limitaciones y no es una herramienta fundamental. A la hora de decidir si la empleamos o no, debemos considerar dos escenarios posibles: Si nuestra aplicacin se va a parecer mucho a lo generado por Grails, podemos usarlo como punto de partida para una primera versin del cdigo, y a partir de ese momento, asumir el control sobre l introduciendo los cambios que sean necesarios. Es importante tener en cuenta que entonces no debemos volver a generar los artefactos, puesto que se perderan nuestros cambios. Si la aplicacin no se parece a lo generado mediante scaffolding, an puede resultar til como consola de administracin o backend , aunque para implementar la lgica de nuestra aplicacin tendremos que partir de cero. Por tanto, antes de generar artefactos de forma automtica es recomendable pararse a pensar en qu tipo de uso vamos a darles despus, ya que si no planificamos nuestra aplicacin podemos vernos en un callejn sin salida intentando que el scaffolding haga cosas para las que nunca fue diseado.

Configuracinde accesoa datos


Como seguro que habrs notado, no le hemos dicho a Grails dnde debe guardar los datos, y sin embargo la aplicacin funciona correctamente. Grails incorpora HSQLDB(http://www.hsqldb.org), una base de datos empotrada escrita ntegramente en Java, para que podamos empezar a trabajar sin tener que contar con un servidor. Sin embargo, en la mayora de los casos tendremos una base de datos y querremos usarla. Para ello editamos el siguiente archivo: grails-app/conf/DataSource.groovy data"ource 6 pooled 7 true dbCreate 7 AupdateA driverClassBame 7 Acom.m(s%l.,dbc.:riverA username 7 Adata0serA pass&ord 7 AdataCassA ; environments 6 production 6 data"ource 6 url 7 A,dbc1m(s%l1@@servidor1<<>D@live:bA ; ; test 6 data"ource 6
Pgina 39

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

url 7 A,dbc1m(s%l1@@servidor1<<>D@test:bA ; development 6 data"ource 6 url 7 A,dbc1m(s%l1@@servidor1<<>D@dev:bA ; ; ;

; Como ves, Grails permite tener entornos distintos (desarrollo, pruebas, produccin) configurados, de forma que por ejemplo: grails war - genera un war de mi aplicacin configurada para el entorno de desarrollo. grails prodwar - genera el war configurado para produccin.

Controladores
Los controladores son los responsables de recibir las solicitudes del usuario, aplicar la lgica de negocio sobre el modelo, y decidir la vista que se debe mostrar a continuacin. Hemos visto que Grails puede generar controladores para gestionar el ciclo de vida de nuestras entidades, pero lgicamente nosotros podemos generar controladores mediante el comando createcontroller: grails create-controller prueba Al ejecutar el comando, Grails generar una clase en grails-app/controllers: grails-app/controllers/PruebaController.groovy: class CruebaController 6 def accion 7 6 render AControlador de pruebas...A ; ; Gracias al empleo de convenciones, todas las clases de la carpeta grailsapp/controllers que se llamen XXXController.groovy respondern a la url correspondiente, en este caso, /Aplicacin/prueba/accion.

Vistas:GroovyServerPages
La vista en una aplicacin MVC es la responsable de mostrar al usuario el estado del sistema y las acciones que tiene a su disposicin. En Grails desarrollamos las vistas mediante GroovyServerPages , una versin simplificada de JSP que permite intercalar
Pgina 40

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

expresiones en el cdigo HTML y emplear una serie de etiquetas al estilo JSTL.

Por ejemplo: grails-app/views/otro/vista.gsp Ehtml> Ehead>...E@head> Ebod(> Eg1set var7Ami'ariableA> Fo( es1 $6ne& :ate(); E@g1set> Ep> #o %ue tengo %ue decir es1 Estrong>$6mi'ariable;E@strong> E@p> E@bod(> E@html> Para invocar esta vista desde un controlador usaramos el mtodo render: grails-app/controllers/OtroController.gsp class *troController 6 def mivista 7 6 render(vie&1GvistaG) ; ;

HelpersparaAJAX
Entre las libreras de etiquetas GSP encontramos varias que nos permiten generar cdigo Javascript en nuestras pginas y realizar llamadas AJAX al servidor. Por ejemplo: Escript t(pe7Ate3t@,avascriptA> $(Gm(divG).onclicH 7 Eg1remote4unction action7Asho&A id7A A @> E@script> Eselect onchange7A$remote4unction( action7GbooHb(nameGI update78success1GgreatGI failure1GohnoG9I params7GGbooHBame7G + this.valueG );A> Eoption>firstE@option> Eoption>secondE@option> E@select>

Pgina 41

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Customtags
Al igual que JSP, GSP soporta el concepto de librera de etiquetas, solo que mucho ms simplificado y elegante. En Grails una librera de etiquetas es una clase Groovy con el nombre XXXTagLib.groovy que se aloja en la carpeta grails-app/taglib. Por ejemplo: grails-app/taglib/SimpleTagLib.groovy: class "imple2ag#ib6 def mitag 7 6attrsI bod( -> out EE AEdiv class7G$6attrs.estilo;G> out EE bod(() out EE AE@div>A ; ; Podramos usar este fragmento en cualquier vista para utilizar nuestro TagLib: Ebod(> Eg1mitag estilo7Aro,oA> Ep> Cual%uier cosa... E@p> E@g1mitag> E@bod(>

Servicios
El equipo de desarrollo de Grails desaconseja (y yo tambin) la inclusin de lgica de negocio en la capa de Control, y recomienda hacerlo mediante servicios. Un servicio es una clase cuyo nombre sigue el patrn XXXService.groovy y que se aloja en la carpeta grails-app/services. Por ejemplo: grails-app/services/UserService.groovy: class 0ser"ervice 6 void activar0suario(0suario u)6 @@lgica del servicio ; ; Para usar el servicio, cualquier controlador, librera de etiquetas, etc puede declarar una variable userService, lo que activar la inyeccin automtica por parte de Spring de la dependencia: grails-app/controllers/UserController.groovy: class 0serController6 def user"ervice def activar 7 6 def u 7 0ser.get(params.id)
Pgina 42

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

user"ervice.activar0suario(u) ; ;

Desplegarnuestraaplicacin
Una vez completado el desarrollo de nuestra aplicacin, podemos desplegarla en cualquier contenedor JavaEE. Para ello necesitaremos generar el archivo WAR mediante el comando: grails prod &ar Este comando compilar todo nuestro cdigo Groovy y Java, y generar un archivo a partir del esqueleto contenido en la carpeta web-app de nuestro proyecto. El nombre del archivo incluir la versin de nuestra aplicacin, de forma que podamos mantener un histrico de versiones. Con esto completamos el breve repaso a Grails. En los siguientes captulos nos adentraremos con una mayor profundidad en los temas que hemos tratado.

Pgina 43

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

4. :o ?u

d ) s sa) r ant s d m$ 6ar

Pgina 44

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

A estas alturas ya deberas tener una impresin de conjunto sobre Grails, y la forma de trabajar para crear aplicaciones web JavaEE con este entorno. En este captulo vamos a profundizar en los principios que hay detrs del framework, explicando el por qu de cada cosa y tratando de guiarte a la hora de disear tus aplicaciones.

Metodologas
Grails es un entorno para desarrollo de aplicaciones web sobre la plataforma Java Enterprise Edition nacido en un contexto muy particular: el de las metodologas giles de desarrollo de software. La idea detrs de estos procesos es que los requisitos de una aplicacin no siempre pueden definirse completamente antes de comenzar la implementacin, y es necesario un ciclo basado en iteraciones cortas y una comunicacin muy fluida con el cliente para que el proyecto vaya bien encaminado desde el principio y no se desve en fecha y/o coste. Se trata de aliviar el desarrollo de software de procesos burocrticos y rgidos que obligan a definir por completo los requisitos, luego disear una solucin, luego implementarla, y luego probarla, siempre por ese orden y terminando completamente una etapa antes de comenzar la siguiente. Hay muchas metodologas giles, pero todas tienen en comn una clara orientacin a gestionarel cambio . Es posible (y frecuente) que el cliente no tenga completamente definidos los requisitos antes de comenzar el desarrollo, y que necesite estar involucrado en el proceso de desarrollo ms all de la reunin de arranque del proyecto. De esta manera, metodologas como eXtremeProgrammingo Scrumincluyen al cliente en las reuniones de seguimiento, y establecen una forma de trabajo en la que la comunicacin fluida garantiza que si se produce un cambio total o parcial en los requisitos el equipo de desarrollo ser capaz de adaptar la aplicacin en un tiempo razonable. Pero para que esto sea posible es necesario contar con herramientas que tambin sean giles, y aqu es donde nacen frameworks como Rubyon Rails, y en el mbito de Java, lenguajes como Groovyy frameworks como Grails. Son herramientas en las que el programador gasta el mnimo tiempo necesario en tareas repetitivas, y en las que un cambio de requisitos no obliga a reescribir toda la aplicacin, porque la mayora del cdigo de infraestructura se genera de forma dinmica mientras la aplicacin se est ejecutando.

El patrnModelViewController
Respecto al diseo, Grails sigue un patrn muy popular sobre todo en el desarrollo de aplicaciones web, denominado Model-View-Controller, o Modelo-Vista-Controlador. Este patrn establece que los componentes de un sistema de software debe organizarse en 3 capas distintas segn su misin:
Pgina 45

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Modelo,o capade datos . Contiene los componentes que representan y gestionan los datos manejados por la aplicacin. En el caso ms tpico, los objetos encargados de leer y escribir en la base de datos. Vista, o capade presentacin . Los componentes de esta capa son responsables de mostrar al usuario el estado actual del modelo de datos, y presentarle las distintas acciones disponibles. Capade control . Contendr los componentes que reciben las rdenes del usuario, gestionan la aplicacin de la lgica de negocio sobre el modelo de datos, y determinan qu vista debe mostrarse a continuacin. Cuando digo que los componentes de la capa de control "gestionanla aplicacinde la lgica de negocio " me refiero a que son responsables de que sta se aplique, lo cual no quiere decir que debamosimplementarla lgicade nuestroscasosde uso en los controladores . Normalmente esta lgica estar implementada en una cuarta capa: Capade servicios . Contiene los componentes encargados de implementar la lgica de negocio de nuestra aplicacin. Cuando trabajamos en Grails, generamos componentes en cada una de las capas y es el entorno el que se encarga de conectar unos con otros y garantizar su buen funcionamiento. Por ejemplo, los componentes de la capa de servicios son clases cuyo nombre termina en "ervice y que se alojan en la carpeta grails-app@services: class #ogin"ervice 6 Cersona do#ogin(userBameI userCass)6 def p 7 Cersona.find5(0serBameAndCass&ord( userBameIuserCass ) if(p)6 p.last#ogin 7 ne& :ate() p.save() ; ; ; Si queremos utilizar este servicio desde un Controlador, simplemente declaramos una variable con el nombre login"ervice y Grails inyectar automticamente una instancia del servicio: class #oginController 6 def login"ervice def login 7 6 def p 7 login"ervice.do#ogin( params.nI params.p) if(p)6 redirect(action1inde3) ;
Pgina 46

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

else6 ; ; ; redirect(action1login4orm)

El resultado de implementar la lgica de negocio en un servicio es que el controlador nicamente tiene que decidir qu vista se muestra en funcin del resultado devuelto por el mtodo do#oginI con lo que nuestros componentes quedan sencillos y fciles de leer y diagnosticar en caso de incidencias.

Inversinde Control(IoC)
La inversin de control es otro patrn utilizado en Grails, segn el cual las dependencias de un componente no deben gestionarse desde el propio componente para que ste slo contenga la lgica necesaria para hacer su trabajo. En el ejemplo anterior hemos visto cmo el Controlador defina una variable con el nombre del servicio que necesitaba emplear, pero no se ocupaba de instanciar el servicio ni de configurarlo de ningn modo antes de poder usarlo. En su lugar, Grails utiliza el contenedor Spring para ese tipo de tareas. Cuando creamos un componente en nuestra aplicacin, Grails configura Spring para que gestione su ciclo de vida (cundo se crea, cuntas instancias se mantienen vivas a la vez, cmo se destruyen, etc.) y sus dependencias (qu otros componentes necesita para realizar su trabajo y cmo conseguirlos). El objetivo de esta tcnica es mantener nuestros componentes lo ms sencillos que sea posible, incluyendo nicamente cdigo que tenga relacin con la lgica de negocio, y dejar fuera todo el cdigo de fontanera. As, nuestra aplicacin ser ms fcil de comprender y mantener.

Pgina 47

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

5. *natom#a d "rai!s4 :a !#n a d comandos

Pgina 48

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Grails no es un framework web al estilo de Struts, sino un entorno "full stack" que nos proporciona componentes para todas las capas de nuestra arquitectura, as como herramientas de generacin de cdigo y de testing entre otras. Por eso incluye Gant (un envoltorio sobre Apache Ant escrito en Groovy) para coordinar el trabajo de todo el entorno.

Con Grails una gran parte del tiempo lo pasaremos en la consola, invocando comandos desde la carpeta de nuestro proyecto. Estos comandos son los que utilizaremos para, por ejemplo, generar el esqueleto de nuestros artefactos, o ejecutar todas las pruebas unitarias y de integracin, o ejecutar la aplicacin en modo desarrollo. Cada vez que ejecutemos el comando: grails 8nombre del script9 Grails buscar un script de Gant con el nombre que hayamos introducido en las siguientes ubicaciones: USER_HOME/.grails/scripts PROJECT_HOME/scripts PROJECT_HOME/plugins/*/scripts GRAILS_HOME/scripts Si encuentra ms de un script con el nombre que hayamos escrito, nos dejar elegir cual queremos ejecutar. Veamos algunos de los comandos principales que podemos invocar sobre nuestro proyecto: clean elimina todas las clases compiladas compile realiza la compilacin de todos los fuentes Groovy y Java de nuestra aplicacin. console lanza una consola Swing que podemos utilizar para ejecutar cdigo de
Pgina 49

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

forma interactiva sobre nuestro proyecto:

create-app Enombre> crea el esqueleto de una nueva aplicacin. create-controller Enombre> crea el esqueleto para un controlador. create-domain-class Enombre> - crea una nueva clase de Entidad. create-integration-test Enombre> - crea el esqueleto para un caso de prueba de integracin. create-plugin Enombre> - crea el esqueleto para desarrollar un plugin. create-script Enombre> - Crea el esqueleto para un nuevo script Gant. create-service Enombre> - Crea el esqueleto para una nueva clase de la capa de servicios. create-tag-lib Enombre> - Crea el esqueleto para una nueva librera de etiquetas. create-unit-test Enombre> - Crea el esqueleto para un caso de pruebas unitarias. doc genera la documentacin javaDoc y GroovyDoc de nuestro proyecto. generate-all Eentidad> - Lanza el scaffolding para la entidad

Pgina 50

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

correspondiente. generate-controller Eentidad> - Genera el controlador CRUD para la entidad correspondiente. generate-vie&s Eentidad> - Genera las vistas CRUD para la entidad correspondiente. help Muestra la lista completa de comandos disponibles. install-plugin Enombre o ruta> - Instala un plugin en nuestro proyecto. Si proporcionamos un nombre en vez de una ruta, buscar el plugin en el repositorio oficial (ver http://grails.org/plugin/home). install-templates Instala en nuestro proyecto las plantillas usadas por Grails para la generacin de artefactos. Una vez instaladas, Grails siempre usar nuestra copia local, de forma que podemos personalizar la generacin de cdigo. install-dependenc( (desde Grails 1.2) descarga una librera a la cach local, por ejemplo: grails install-dependenc( m(s%l1m(s%l-connector-,ava1=. .= list-plugins Muestra la lista de plugins disponible en el repositorio oficial. run-app Ejecuta nuestra aplicacin en el contenedor Tomcat includo con Grails. run-&ar Genera un archivo WAR de nuestra aplicacin y lo despliega en el contenedor Tomcat includo con Grails. A diferencia de run-app, en esta modalidad no se recargarn automticamente los archivos que modifiquemos. schema-e3port Utiliza la herramienta SchemaExport de Hibernate para generar el cdigo DLL de nuestro esquema. set-version Enumero> Modifica la versin actual de nuestro proyecto. El nmero de versin se refleja entre otros sitios en el nombre del archivo WAR generado cuando empaquetamos nuestra aplicacin. shell Ejecuta una terminal Groovy que podemos usar para lanzar comandos de forma interactiva en nuestra aplicacin:

Pgina 51

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

stats Muestra una estadstica sobre nuestro proyecto mostrando nmero de archivos segn tipo y el total de lneas de cdigo:

test-app Ejecuta todos los casos de prueba definidos en nuestro proyecto, generando un informe con el resultado del proceso. uninstall-plugin Enombre> Elimina el plugin correspondiente de nuestra aplicacin. upgrade actualiza nuestra aplicacin para adaptarla a una versin superior de Grails. &ar genera el archivo WAR (Web Application aRchive) de nuestra aplicacin, que podemos desplegar en cualquier servidor de aplicaciones JavaEE. A lo largo de los siguientes captulos iremos mostrando con ms profundidad el funcionamiento de la mayora de estos comandos, a medida que los utilicemos en los distintos ejemplos. Para una lista completa y actualizada te recomiendo la documentacin oficial del proyecto: http://grails.org/Documentation

Pgina 52

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Personalizarla generacinde cdigo


Como has visto, la mayora de los scripts de Grails sirven para generar cdigo de una u otra manera, ya sea creando artefactos o construyendo controladores y vistas mediante scaffolding para manipular nuestro modelo de datos. El cdigo generado es til en la mayora de las situaciones, pero existen otras en las que necesitamos tener ms control sobre el proceso. Como vimos en el primer captulo, el objetivo de Grails es ser sencillo en la superficie, pero manteniendo la posibilidad de accedera las profundidadessi necesitamos un comportamiento especfico. Siguiendo esa filosofa se ha incluido el comando install-templates. Si instalamos las plantillas en una aplicacin, Grails copiar los archivos que utiliza para generar cdigo en la carpeta src@templates de nuestro proyecto, incluyendo: src@templates@artifacts plantillas para generar los distintos tipos de artefacto: Controller.groovy DomainClass.groovy Filters.groovy Script.groovy Service.groovy TagLib.groovy Tests.groovy WebTest.groovy src@templates@scaffolding plantillas para el scaffolding de una clase del modelo de datos: Controller.groovy create.gsp edit.gsp list.gsp renderEditor.template (crea el campo del formulario HTML en funcin del tipo de dato de cada propiedad) show.gsp src@templates@&ar plantilla para generar la aplicacin JavaEE web.xml

En cada una de las plantillas vers que se utilizan variables para referirse en cada caso al artefacto que se est generando as como otros datos relacionados. Por
Pgina 53

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ejemplo, la plantilla DomainClass.groovy tiene esta pinta: Jartifact.pacHageJ class Jartifact.nameJ 6 static constraints 7 6 ; ;

Lo importante a tener en cuenta es que una vez que hemos instalado las plantillas en nuestra aplicacin, Grails usar siempre la copia local para generar cdigo, de forma que podemos modificarlas para controlar el proceso de generacin alterando, por ejemplo, el aspecto que tienen las vistas por defecto, o el editor utilizado para un tipo de dato particular.

Pgina 54

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

6. Con1iguracin

Pgina 55

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Como hemos visto, Grails es un entorno en el que se prima la convencin sobre la configuracin. Gracias a este principio, para definir, por ejemplo, los Controladores de nuestra aplicacin, no necesitamos declararlos en ningn archivo XML o de ningn tipo. En lugar de eso, cualquier clase que se llame [LoQueSea]Controller y est en la carpeta grails-app@controllers ser tratada como un controlador y estar asociado con un conjunto de URLs particular. Tampoco es necesario especificar qu vista hay que mostrar para una accin particular, ya que Grails buscar automticamente aquella que se llame igual que la accin y est en una carpeta con el mismo nombre que el controlador (ms sobre esto en el captulo 9) A pesar de esto, en Grails s existen archivos de configuracin que podemos manipular para modificar el comportamiento del entorno. Estos archivos se almacenan en la carpeta grails-app@conf, y a continuacin repasamos el contenido y el propsito de los ms importantes. Grails contempla el uso de entornos de ejecucin, de forma que podamos establecer valores de configuracin diferentes para desarrollo, pruebas y produccin.

El archivoConfig.groovy
El archivo grails-app@conf@Config.groov( contiene los parmetros de configuracin general de nuestra aplicacin. Se trata de un archivo de ConfigSlurper (http://groovy.codehaus.org/ConfigSlurper), lo cual permite la declaracin de variables y el uso de tipos de datos en la configuracin. Cualquier parmetro que definamos en este archivo estar disponible desde cualquier artefacto de la aplicacin a travs del objeto global grailsApplication.config. Por ejemplo, si definimos la siguiente variable: com.imagina&orHs.miCarametro 7 AdatoA podremos acceder desde cualquier controlador, vista, servicio, etc a su valor mediante la expresin grailsApplication.config.com.imagina&orHs.miCarametro Existe una serie de parmetros predefinidos que podemos utilizar para modificar el comportamiento de Grails: grails.config.locations Ubicaciones en las que queremos guardar otros archivos de configuracin para que se fundan con el principal. grails.enable.nativeKascii Si el valor es true, Grails usar native2ascii para convertir los archivos properties a unicode (el compilador y otras utilidades Java slo puede manejar archivos que contengan caracteres Latin-1 y/o Unicode). grails.vie&s.default.codec El formato por defecto para nuestras GSPs. Puede valer 'none' (por defecto),'html' o 'base64'. grails.vie&s.gsp.encoding Codificacin por defecto de nuestros archivos GSP (por defecto es 'utf-8').
Pgina 56

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

grails.mime.file.e3tensions Habilita el uso de la extensin en la url para fijar el content type de la respuesta (por ejemplo, si aadimos '.xml' al final de cualquier url Grails fijar automticamente el content type a 'text/xml', ignorando la cabecera Accept del navegador). grails.mime.t(pes Un Map con los tipos mime soportados en nuestra aplicacin. grails.server0.# La parte "fija" de nuestros enlaces cuando queramos que Grails genere rutas absolutas. grails.&ar.dest4ile Ruta en la que grails war debera generar el archivo WAR de nuestra aplicacin. grails.&ar.dependencies Permite personalizar la lista de libreras a incluir en el archivo WAR. grails.&ar.,ava=.dependencies Permite personalizar la lista de libreras a incluir en el archivo WAR para el JDK1.5 y superiores. grails.&ar.cop(2oLebApp Permite controlar qu archivos de la carpeta webapp de nuestro proyecto se deben copiar al archivo WAR. grails.&ar.resources Permite personalizar el proceso de generacin del WAR, especificando tareas previas en una closure mediante cdigo Ant builder.

Configuracinde log4j
Grails emplea log4j para la generacin de trazas, y proporciona (a partir de la versin 1.1) un DSL para incluir en Config.groovy la configuracin de umbrales y appenders. Por ejemplo: import org.apache.logM,.N logM, 7 6 root 6 error() ; appenders 6 appender ne& .olling4ileAppender( name1Garchivo.otadoGI ma34ile"i/e1 >KMI fileBame1G@var@log@grails@tra/as.logG ) ; infoGorg.codehaus.groov(.grails.&eb.servletGI Gorg.codehaus.groov(.grails.&eb.pagesG &arn Gorg.mortba(.logG ; Esta configuracin establece un umbral por defecto (root logger) de 'error', y de 'info' para los loggers de Controladores y GSPs, y de 'warn' para el de Jetty. Adems crea
Pgina 57

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

un appender de tipo RollingFileAppender que proporciona rotado automtico de archivos (ms informacin sobre log4j en http://logging.apache.org/log4j).

Configuracinde GORM
Como veremos en el captulo 7, GORM es el gestor de persistencia de Grails. Se encarga de mantener el estado de nuestras entidades en la base de datos. A partir de Grails 1.2 es posible establecer una configuracin genrica de GORM que ser aplicada a todas las clases persistentes salvo que definan lo contrario: @@Cuestiones sobre el mapeo de datos1 grails.gorm.default.mapping 7 6 cache true id generator1Gse%uenceG Guser-t(peG( t(pe1org.hibernate.t(pe.OesBo2(peI class15oolean) ; @@Constraints grails.gorm.default.constraints 7 6 GNG(nullable1trueIblanH1falseIsi/e1 ..K>) ; @@+rupos de constraints1 grails.gorm.default.constraints 7 6 te3tos(nullable1trueIblanH1falseIsi/e1<.. >>) ;

El archivoDataSource.groovy
Grails es Java, y por tanto la configuracin de acceso a datos recae en ltima instancia en JDBC. El archivo :ata"ource.groov( contiene los parmetros de conexin con la base de datos que vayamos a utilizar en cada entorno: data"ource 6 driverClassBame 7 Gcom.m(s%l.,dbc.:riverG pooled 7 true dbCreate 7 GupdateG //Desde Grails 1.2: properties 6 ma3Active 7 => ma3Pdle 7 K= minPdle 7 = initial"i/e 7 = minEvictablePdle2ime)illis 7 D>>>> time5et&eenEviction.uns)illis 7 D>>>> ma3Lait 7 >>>>
Pgina 58

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; ; environments 6 development 6 url 7 ,dbc1m(s%l1@@localhost1<<>D@dev-schema username 7 dev pass&ord 7 dev-pass ; test6 url 7 ,dbc1m(s%l1@@localhost1<<>D@test-schema username 7 test pass&ord 7 test-pass ; production 6 ,ndiBame 7 A,ava1comp@env@mi:ata"ourceA ; ; En el primer bloque data"ource definimos los valores genricos, que podremos sobrescribir despus en cada uno de los entornos. De esta manera, usamos bases de datos distintas en desarrollo, pruebas y produccin. Fjate en que para produccin estamos definiendo un DataSourceJNDI , en lugar de conexin directa. A partir de Grails 1.2, podemos adems definir varios parmetros de bajo nivel relacionados con la gestin del pool de conexiones, como el nmero inicial de conexiones o el tiempo que debe permanecer una conexin inactiva antes de asumir que no la estamos usando y eliminarla del pool. El valor de dbCreate determina la forma en que Grails debera o no generar el esquema de la base de datos automticamente. Los valores posibles son: create-drop El esquema se crear cada vez que arranquemos el contexto de nuestra aplicacin, y ser destruido al detenerlo. create Crea el esquema si no existe, pero no modifica el esquema existente (aunque s borrarlos datosalmacenados). update Crea la base de datos si no existe, y actualiza las tablas si detecta que se han aadido entidades nuevas o campos a las existentes.

El archivoBuildConfig.groovy
Desde Grails 1.1, podemos utilizar el archivo grailsapp@conf@5uildConfig.groov( para controlar distintos aspectos del proceso de compilacin como las rutas de trabajo y la resolucin de dependencias: grails.&orH.dir7A@tmp@&orHA grails.plugins.dir7A@usr@local@grails@plgA
Pgina 59

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

grails.pro,ect.test.reports.dir7A@usr@local@grails@rptA grails.plugin.repos.discover(.m(.epositor(7 Ahttp1@@svn.codehaus.org@grails@trunH@grails-testplugin-repoA grails.plugin.repos.distribution.m(.epositor(7 Ahttps1@@svn.codehaus.org@grails@trunH@grails-testplugin-repoA

Configuracinde depencencias
A partir de Grails 1.2, podemos utilizar un nuevo DSL para definir en BuildConfig.groovy cmo deben resolverse las dependencias de nuestra aplicacin. As, podemos pedir a Grails que acceda a los repositorios Maven para descargar los archivos JAR que necesite nuestra aplicacin sin necesidad de utilizar Ivy o Maven explcitamente. Se distinguen cinco mbitos distintos para la configuracin de dependencias: build: Dependencias necesarias para la construccin del proyecto compile: Dependencias durante la compilacin runtime: Dependencias necesarias para tiempo de ejecucin (pero no de compilacin) test: Dependencias necesarias para la ejecucin de tests, pero no en ejecucin. provided: Dependencias necesarias durante el desarrollo, pero no para construir el WAR. Por defecto slo buscar en la instalacin local de Grails, pero podemos configurar el sistema para usar repositorios remotos, usando Maven o Ivy.

Este es el aspecto que tendr el archivo por defecto:


grails.project.dependency.resolution = { // inherit Grails' default dependencies inherits "global" // Ivy log level: error, arn,info,debug,verbose log " arn" repositories { grails!o"e#$ // unco"". belo to enable re"ote dep. resolution // fro" public %aven repositories //"aven&entral#$ //"aven'epo"http://snapshots.repository.codehaus.o rg" //"aven'epo "http://repository.codehaus.org" //"aven'epo "http://do nload.java.net/"aven/(/" //"aven'epo "http://repository.jboss.co"/"aven(/
Pgina 60

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

) dependencies { // specify dependencies here under either // 'build', 'co"pile', 'runti"e', 'test' or // 'provided' scopes eg. // runti"e 'co"."ys*l:"ys*l+connector+java:,.-.,' ) )

Si hemos instalado algn plugin con una dependencia que entra en conflicto con nuestra aplicacin, podemos redefinirla:
plugin#"hibernate"$ { co"pile#'org.hibernate:hibernate+core:....-.G/'$ { e0cludes 'ehcache', '0"l+apis', 'co""ons+logging' ) co"pile 'org.hibernate:hibernate+annotations:..1.2.G/', 'org.hibernate:hibernate+co""ons+annotations:....2.ga' runti"e 'javassist:javassist:..1.G/' )

Pgina 61

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

7. .! mod !o d

datos4 "/0&

Pgina 62

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El modelo de datos en una aplicacin Grails est compuesto por las clases del Dominio (yo prefiero el trmino Entidades), que se ubican en la carpeta grailsapp@domain. Grails utiliza GORM (Grails Object RelationalMapping ), un gestor de persistencia escrito en Groovy, para controlar el ciclo de vida de las entidades y proporcionar una serie de mtodos dinmicos (se crean en tiempo de ejecucin para cada entidad) que facilitan enormemente las bsquedas. GORM est construido sobre Hibernate , una herramienta de mapeo objeto-relacional, que se encarga de relacionar las entidades de tu clase con tablas de una base de datos, y las propiedades de tus entidades con campos en las tablas. Cada operacin que realices sobre los objetos de tu modelo de datos ser traducida por Hibernate a las sentencias SQL necesarias para quedar reflejado en la base de datos. En Hibernate se maneja el concepto de sesinde usuario , que representa una unidad de trabajo a realizar. Cuando se inicia una sesin se reserva un espacio especfico de memoria para almacenar los objetos que se estn manipulando, y la secuencia de instrucciones SQL que se deben ejecutar, y cuando termina la sesin se lanzan todas las consultas contra la base de datos para hacer permanentes los datos realizados. Es importante que conozcas la forma de trabajar de Hibernate, pero no te preocupes ms por l, porque Grails crea automticamente una sesin de Hibernate para cada peticin atendida por nuestra aplicacin, y la cierra cuando la peticin ha terminado de atenderse, justo antes de enviar la respuesta al navegador. No es necesario manipular Hibernate directamente. Si no te gusta Hibernate o necesitas incluir tu aplicacin clases de entidad definidas con JPA puedes utilizar el soporte para esta tecnologa de persistencia mediante un plugin especfico. Tienes ms informacin en http://www.grails.org/JPA+Plugin

Crearentidades
Todas las clases groovy que se encuentren en la carpeta grails-app@domain sern tratadas por GORM como entidades, por tanto podemos generarlas directamente creando el archivo fuente correspondiente o mediante el comando: grails create-domain-class 8nombre9 Utilizar el comando tiene la ventaja de que Grails generar el esqueleto para nuestra clase, que tendr ste aspecto: class 8nombre9 6 static constraints 7 6 ; ; Lo que tendremos que hacer a continuacin es definir las propiedades de la clase, y GORM se encargar del resto:
Pgina 63

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

generar la tabla correspondiente en la base de datos con los campos necesarios para almacenar cada propiedad y proporcionar los mtodos de bsqueda y modificacin que nos permitan manipular nuestra entidad. Por ejemplo, si definimos una entidad como esta: class 0suario 6 "tring nombre "tring apellidos Pnteger edad :ate fechaBacimiento ; GORM crear automticamente una tabla usuario en la base de datos con los campos correspondientes. Adems, aadir un campo id a nuestra clase (no tenemos que hacerlo nosotros) y se encargar de generar un valor nico secuencial para cada instancia de esta clase. As, podremos recuperar un Usuario mediante: def u 7 0suario.get(<) No ser necesario por tanto ningn archivo de configuracin para gestionar el comportamiento de Hibernate, ya que GORM se encargar de realizar la configuracin en tiempo de ejecucin. A continuacin vamos a ver cmo utilizando una serie de convenciones podemos definir en la propia clase de entidad todos los aspectos de nuestro modelo de datos: relaciones, composiciones, dependencias, tipos de datos, validaciones, y mucho ms.

Validaciones
GORM nos permite restringir los valores que pueden asignarse a las propiedades de cada entidad, mediante una propiedad esttica con el nombre constraints ("restricciones"). En realidad, las constraints valen para ms que eso, ya que se utilizarn tambin a la hora de crear el esquema de datos (por ejemplo, en funcin del tamao de un String Hibernate decidir si crear un campo VARCHAR o LONGTEXT) y para la generacin de vistas mediante scaffolding. Formalmente, la propiedad constraints es una closure en la que se definen las reglas de validacin de cada campo, por ejemplo: class Cersona 6 "tring nombre "tring apellidos "tring userBame "tring userCass "tring email Pnteger edad
Pgina 64

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

static constraints 7 6 nombre(blanH1falseIsi/e1=..=>) apellidos(blanH1falseIsi/e1=..=>) userBame(blanH1falseIsi/e1D.. K) userCass(blanH1falseIsi/e1D.. K) email(email1true) edad(min1 !) ; ; Cada vez que se pretenda guardar una instancia de Cersona invocando al mtodo save, GORM comprobar que todos los valores de las propiedades cumplen con las restricciones definidas en la clase. Desde la versin 1.2, podemos incluir el parmetro fail*nError en la llamada a save para que GORM lance una excepcin en caso de que algn valor no pase la validacin: tr(6 ; catch('alidationE3ception 3)6 @@#a validacin ha fallado. ; persona.save(fail*nError1true)

Para aplicar las restricciones Grails utiliza Apache Commons Validator (http://commons.apache.org/validator). Las reglas que podemos definir son: blanH tendremos que poner bank:false si el campo no admite cadenas de texto vacas. creditCard obliga a que un campo String contenga valores de nmero de tarjeta de crdito vlidos. displa( fijando su valor a false, evitamos que la propiedad se muestre al generar las vistas para Scaffolding. email obliga a que un campo de texto tenga una direccin de correo electrnico vlida. in#ist obliga a que el valor del campo est entre los de una lista cerrada. Por ejemplo: departamento(in#ist18G"istemasGIG:esarrolloG9) matches obliga a que el valor del campo satisfaga una determinada expresin regular: telefono)ovil(matches1AD8 -?96!;A) ma3 garantiza que el valor de este campo no ser mayor que el lmite propuesto. ma3"i/e obliga a que el valor tenga un tamao menor que el indicado.
Pgina 65

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

min garantiza que el valor del campo no ser menor que el lmite propuesto. min"i/e obliga a que el valor tenga un tamao mayor que el indicado. notE%ual El valor de la propiedad no podr ser igual al indicado. nullable Por defecto, Grails no permite valores nulos en las propiedades de una entidad. Para cambiar este comportamiento habr que fijar nullable1true en las propiedades que deseemos. range Permite restringir los valores posibles para una propiedad. Por ejemplo: edad(range1 !..DM) scale fija el nmero de decimales para nmeros de coma flotante. si/e permite restringir el tamao mnimo y mximo a la vez (IMPORTANTE: no se puede utilizar junto con blank o nullable): pass&ord(si/e1D.. K) uni%ue garantiza que los valores de esta propiedad sean nicos. Ten encuenta que se har una consulta a la base de datos en cada validacin. url obliga a que el valor de la propiedad sea un String que represente una URL vlida. validator permite definir validaciones especiales para casos no cubiertos por todas las anteriores: numeroCar( validator16 return(it QK) 77 > ;) A partir de la versin 1.2, podemos establecer restricciones por defecto en el archivo Config.groovy , que sern heredadas por todas las entidades: grails.gorm.default.constraints 7 6 GNG(nullable1trueIblanH1false) ;

Sobrelos mensajesde error


Cuando Grails aplica las reglas de validacin sobre los Tienes ms informacin sobre internacionalizacin de aplicaciones campos de nuestra entidad, utilizar los archivos de Grails en el captulo 15. recursos de la carpeta grails-app@i !n de nuestro proyecto para generar mensajes de error. De esta manera, tendremos nuestra aplicacin compatible con distintos idiomas desde el principio. Si queremos modificar el mensaje para alguna restriccin en particular, tendremos que editar los archivos correspondientes a los idiomas que queramos y aadir un mensaje para la clave asociada a dicha regla. Por ejemplo, si para la clase Cersona queremos cambiar el mensaje que sale cuando se introduce un nombre vaco, tendremos que buscar el mensaje asociado a la clave: Cersona.nombre.blanH
Pgina 66

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

En general, Grails buscar claves con este formato: 8Clase9.8Cropiedad9.8.estriccin9 Si no encuentra ningn mensaje asociado a la clave buscada, mostrar el mensaje por defecto que est asociado a la clave default.invalid.8.estriccin9.message

Cmomapearasociaciones
Las relaciones entre entidades permiten modelar las asociaciones de tipo uno-a-uno, uno-a-muchos y muchos-a-muchos que existan en nuestro modelo de datos. Veamos cada uno en detalle:

RelacionesUnoA-Uno
Este es el tipo de relacin que existe, por ejemplo, entre un coche y su conductor: cada coche tiene un nico conductor y un conductor slo puede conducir un coche cada vez. En Grails se representa esta situacin a travs del tipo de dato de cada propiedad: class Coche 6 Conductor conductor ; class Conductor 6 Coche coche ; Al declarar una propiedad de tipo Conductor en la clase Coche, GORM crear un campo en la tabla coche para almacenar la clave primaria del Conductor asociado. Ten en cuenta que si definimos la relacin de esta manera no se producirn actualizaciones en cascada, es decir, que si borramosun coche no se eliminartambin su conductor. De hecho al intentar borrar el Coche saltara una excepcin por violacin de restriccin de clave fornea, y tendramos que borrar explcitamente el Conductor para poder eliminar el Coche. ste es el comportamiento deseado en la mayora de los casos, pero si necesitamos que se produzca un borrado en cascada podemos conseguirlo representando nuestra relacin de esta manera: class Coche 6 Conductor conductor ; class Conductor 6 static belongs2o 7 8coche1Coche9
Pgina 67

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; La propiedad esttica belongs2o establece por convenio que existe una relacin de subordinacin entre los coches y sus conductores, de manera que si borramos un Coche se eliminar tambin su Conductor. belongs2o debe ser un Map en el que se definirn todas las relaciones en las que participa esta clase. Cada clave ser el nombre de la propiedad que se refiera al propietario de este objeto, y el valor asociado a dicha clave la clase en la que GORM debe buscar tal propietario.

RelacionesTieneUn
Desde la versin 1.2, Grails incluye las relaciones Tiene-Un: class Cersona 6 "tring nombre static has*ne 7 8direccion1:ireccion9 ; class :ireccion 6 "tring calle "tring codCostal ; La diferencia entre usar has*ne y declarar una propiedad de tipo Direccion en Persona, como vimos en el apartado anterior, est en que la clave fornea se guardar en Direccion, en lugar de en Persona. Por tanto, la tabla direccion de la base de datos tendr una columna personaRid.

RelacionesUnoA-Muchos
Las relaciones de este tipo se dan, por ejemplo, entre los libros y sus autores: cada libro tiene un nico autor, pero cada autor puede haber escrito varios libros. La forma de representar esto en nuestro modelo de datos sera la siguiente: class #ibro 6 "tring titulo ; class Autor 6 "tring nombre static has)an( 7 8libros1#ibro9 ; La propiedad has)an( es un Map en el que cada clave es el nombre de una coleccin y el valor asociado es el tipo de los objetos contenidos en la coleccin. GORM crear un mtodo add2oAA55CC() por cada relacin:

Pgina 68

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def autor 7 ne& Autor(nombre1G:avid A. 'iseG) .add2o#ibros(ne& #ibro(titulo1G+oogleI the stor(G)) .save() Este cdigo crear un objeto Autor y otro #ibro, y los guardar (los dos) en la base de datos al invocar el mtodo save() sobre el Autor. En este caso tenemos una relacin uno-a-muchos unidireccional: podemos navegar por los libros de un autor, pero no podemos obtener el autor de un libro concreto: def a 7 Autor.get( ) a.libros.each 6 println it.titulo ; IMPORTANTE : la poltica por defecto de Hibernate es no cargar en memoria los objetos #ibro de un Autor hasta que explcitamente naveguemos por la coleccin (carga perezosa ). De esta manera evitamos la creacin de un montn de instancias cada vez que accedemos al Autor. Sin embargo, si ste no es el comportamiento deseado podemos cambiarlo (activar la cargaanticipada ) en la propiedad mapping: class Autor 6 static has)an( 7 8libros1#ibro9 static mapping 7 6 libros fetch1A,oinA ; ; En este caso, cada vez que se cargue un autor, se cargarn tambin sus libros desde la base de datos. Esto conlleva el riesgo de que, si no tenemos cuidado, podemos terminar con demasiados objetos en memoria y tener problemas de rendimiento. Para que la relacin sea bidireccional (poder acceder al autor desde el libro y a los libros desde el autor) tendremos que declararla en ambas clases: class Autor 6 static has)an( 7 8libros1#ibro9 ; class #ibro 6 "tring titulo Autor autor ; En este caso podremos acceder al autor de un libro, pero no se producirn borrados en cascada de los libros al borrar el autor. Si queremos que sea as tendremos que utilizar belongs2o igual que en la relacin uno-a-uno:
Pgina 69

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

class Autor static ; class #ibro "tring static ;

6 has)an( 7 8libros1#ibro9 6 titulo belongs2o 7 8autor1Autor9

RelacionesMuchosa-Muchos
Este es el tipo de relacin que existe entre las personas y las asociaciones: cada asociacin puede tener varios miembros, y cada persona puede ser miembro de distintas asociaciones. Para representar esta relacin en GORM tenemos que: Declarar una propiedad has)an( en ambos lados de la relacin. Declarar una propiedad belongs2o en el lado subordinado de la relacin. Por ejemplo: class Asociacion 6 "tring nombre static has)an( 7 8miembros1Cersona9 ; class Cersona 6 "tring nombre static has)an( 7 8asociaciones1Asociacion9 static belongs2o 7 Asociacion ; Para representar este tipo de relaciones, GORM necesitar crear una tabla adicional (aparte de asociacin y persona) en la que almacenar los pares de ids que estn ligados. De esta manera, podramos crear objetos as: def a 7 ne& Asociacion(nombre1G,avaFispanoG) .add2o)iembros(ne& Cersona(nombre1GBacho 5ritoG)) .save() y GORM almacenara tanto la Asociacin como la Persona en la base de datos. Sin embargo, si lo hacemos al revs: def p 7 ne& Cersona(nombre1GBacho 5ritoG) .add2oAsociaciones(ne& Asociacion(nombre1G,FG)) .save() GORM slo guardaren la basede datosel objetoPersona,no la Asociacin . Esto es as porque hemos dicho que la relacin est gobernada por la clase Asociacin (hay un belongs2o en la case Persona), de manera que sta es la clase encargada de las actualizaciones en cascada.
Pgina 70

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Comomapearcomposiciones
Muchas veces necesitamos crear una clase para representar una cierta caracterstica de nuestras entidades pero no queremos crear una tabla en la base de datos para ella, porque no representa en s misma una entidad. El caso tpico es el de los datos de contacto de una persona. Por ejemplo: class Cersona6 "tring nombre :ireccion direccion ; class :ireccion6 "tring calle "tring numero "tring portal "tring piso "tring letra "tring codigoCostal "tring municipio "tring provincia "tring pais ; Si definimos la clase :ireccion en un archivo independiente :ireccion.groov( dentro de la carpeta grails-app@domain, GORM lo tratar como una relacin unoa-uno y crear una tabla en la base de datos para guardar todas las direcciones. Sin embargo, lo deseable sera que todos los campos se guardasen en la tabla persona, pero manteniendo la posibilidad de acceder a ellos a travs de una propiedad direccin en cada instancia. Este tipo de relacin se denomina composicin . Para representarla lo nico que debemos hacer es definir la clase Direccion a continuacin de la clase Persona en el mismoarchivograils-app@domain@Cersona.groov(. Entonces GORM almacenar los campos de la clase :ireccion en la tabla persona, aunque luego nos permitir acceder a ellos mediante una propiedad de tipo :ireccion, en lugar de individualmente.

Cmomapearherencia
GORM soporta la herencia entre entidades: class Cersona 6 "tring nombre "tring apellidos ;

Pgina 71

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

class Autor e3tends Cersona 6 static has)an( 7 8libros1#ibro9 ; class Conductor e3tends Cersona 6 Coche coche ; El comportamiento por defecto de Hibernate en este caso es usar una misma tabla para todas las clases de una misma jerarqua, aadiendo un campo class que permita distinguir el tipo de cada instancia. Existe la posibilidad de configurar GORM para que cree una tabla para cada clase mediante la propiedad mapping: class Cersona 6 "tring nombre "tring apellidos ; class Autor e3tends Cersona 6 static mapping = { table = 'autor' } static has)an( 7 8libros1#ibro9 ; class Conductor e3tends Cersona 6 static mapping = { table = 'conductor' } ; Coche coche

Elegir un sistema u otro depende de nuestras necesidades, porque cada uno tiene sus inconvenientes: Usar una tabla por jerarqua implica que no podemostenercamposno nulos en nuestras entidades. Usar una tabla por clase implica un peor rendimiento a la hora de hacer consultas porque aumenta el nmero de tablas y joins necesarios.

Pgina 72

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Utilizaresquemasde datosheredados
En muchas ocasiones desarrollamos aplicaciones que deben gestionar esquemas de datos existentes, de manera que no es posible dejar a GORM crear tablas y campos sino que nuestras entidades deben mapearse a una base de datos existente. En este caso podemos personalizar el mapeo definiendo una propiedad esttica mapping en nuestra entidad: class Cersona6 "tring nombre "tring apellidos :epartamento departamento static mapping 7 6 table GtbRusuariosG nombre column1GB*)5.ER0"0A.P*GI t(pe1te3t apellidos column1 GACE##P:*"R0"0A.P*G departamento column1 GP:R:ECA.2A)EB2*G ;

Los tipos de datos que podemos usar en cada campo son los soportados por Hibernate. Cada uno de ellos se traducir despus al tipo SQL nativo de la base de datos que estemos usando en cada caso: TipoJava Tipos nativos TipoHibernate integer, long, short, float, double, character, byte, boolean, yes_no, true_false string date, time, timestamp TraduccinSQL Tipo nativo correspondiente a la B.D. VARCHAR DATE, TIME, TIMESTAMP TIMESTAMP, DATE NUMERIC, NUMBER

java.lang.String java.util.Date

java.util.Calendar

calendar, calendar_date

java.math.BigDecimal java.math.BigInteger

big_decimal big_integer

Pgina 73

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

java.util.Locale java.util.TimeZone java.util.Currency java.lang.Class Arrays de bytes

locale timezone currency class binary

VARCHAR

VARCHAR TIPO BINARIO SQL CLOB / TEXT TIPO BINARIO SQL

java.lang.String java.util.Serializable

text serializable

Tienes ms informacin sobre los tipos soportados en la web de Hibernate: http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping-types.html

Operacionessobreel modelode datos


Una vez definido nuestro modelo de datos, necesitaremos conocer la herramienta que GORM pone a nuestra disposicin para manipular nuestras entidades. Veamos por separado cmo utilizarlas para actualizar nuestros datos y para realizar consultas.

Actualizaciones
Todas las entidades en una aplicacin Grails poseen un mtodo save que sirve para insertar el registro en la base de datos o para actualizarlo si ya exista: def p 7 ne& Cersona(nombre1GCaco CSre/G) p.save() p 7 Cersona.find5(Bame(GCaco CSre/G) p.nombre 7 GCaco "Tnche/G p.save() Es muy importante tener en cuenta que el hecho de invocar al mtodo save en nuestro objeto no significa que se vaya a lanzar el SQL correspondiente en ese mismo instante . Hibernate retrasa la ejecucin de todas las operaciones hasta que se cierra la sesin (justo al final de procesar la peticin).
Pgina 74

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Si queremos que los datos se enven a la base de datos en el mismo momento en que invocamos a save, podemos utilizar el argumento flush: def p 7 ne& Cersona(nombre1G-uan +on/Tle/G) p.save(flush1true) Para eliminar un registro, disponemos del mtodo delete: def p 7 Cersona.get( ) p.delete() Al igual que save(), podemos pasar el argumento flush a delete para enve la orden SQL de forma inmediata. As que, si no proporcionamos el argumento flush los datos no se guardan o eliminan de la base de datos hasta que termina de procesarse la peticin HTTP. Pero entonces, qu ocurre si una peticin tarda varios segundos en procesarse y los datos son alterados por otra peticin antes de que la primera termine? Para tratar este problema GORM soporta dos tipos de bloqueo para los datos que se estn manipulando. Los vemos a continuacin.

Bloqueosde datos
El comportamiento por defecto de GORM es aplicar bloqueooptimista sobre nuestros datos. Para implementar este comportamiento, cada instancia tendr un campo version que se incrementar cada vez que se modifiquen los valores de sus propiedades, y se almacenar en la base de datos. Cada vez que hagamos una llamada a save() sobre un objeto, Hibernate comparar el valor de la versin del objeto en memoria con el almacenado en la base de datos, y si no coinciden asumir que algn otro proceso (otra peticin HTTP) ha modificado el objeto despus de que este fuera cargado en memoria, as que Hibernate har el rollback de la transaccin y lanzar una "tale*b,ectE3ception. La ventaja de este sistema es que en caso de grandes volmenes de trfico nos protege de corrupciones de datos por modificaciones concurrentes, sin requerir bloqueos de tablas en la base de datos, pero a cambio tendremos que lidiar nosotros con las excepciones en situaciones de alta concurrencia. En cambio, el bloqueopesimista consiste en que cuando carguemos un objeto desde la base de datos, Hibernate solicitar a la base de datos el bloqueo de la fila correspondiente en la tabla, de forma que otras operaciones (incluso de lectura) sobre ella tendrn que esperar a que termine de ejecutarse la operacin actual. Este sistema es totalmente seguro respecto a la corrupcin de datos, pero provoca un rendimiento sensiblemente peor de la aplicacin. Para utilizar el bloqueo pesimista debemos invocar el mtodo locH() que tienen todas las clases de entidad: def p 7 Cersona.locH(<M) p.nombre 7 GCaco "Tnche/G
Pgina 75

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

p.save()

Consultas
Como hemos comentado, en Grails todas la clases que pertenecen al modelo de datos poseen ciertos mtodos de instancia que facilitan su manipulacin, de los cuales ya hemos mencionado algunos como save() o delete(). GORM tambin inyecta una serie de mtodos estticos (de clase) en nuestras clases persistentes para hacer consultas sobre los datos almacenados en la tabla o tablas correspondientes. Veamos algunas formas de obtener instancias de nuestras clases de entidad: def gente @@*btener la lista completa de instancias1 gente 7 Cersona.list() @@Con paginacin1 gente 7 Cersona.list(offset1 >Ima31K>) @@Con ordenacin1 gente 7 Cersona.list(sort1GnombreGIorder1GascG) @@Cargar por P:1 def p 7 Cersona.get(<K) gente 7 Cersona.getAll(KI!I<M) Cuando no conocemos el identificador de la instancia o instancias que buscamos, necesitamos hacer consultas, que en GORM puede enfocarse de tres maneras distintas en funcin de la complejidad que necesitemos:

DynamicFinders
Los Dynamic Finders ('localizadores dinmicos') tienen el mismo aspecto que los mtodos estticos, perono existenen realidad . Cuando son invocados la primera vez se generan dinmicamente mediante la sntesis de bytecodes. Por ejemplo, supongamos que hemos definido la siguiente entidad: class :epartamento 6 "tring nombre "tring cdigo :ate fechaCreacion
Pgina 76

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

5oolean es2ecnico ; Entonces, en nuestra aplicacin, podramos invocar mtodos con el prefijo findByo findAllByy combinaciones de operadores y propiedades. La diferencia entre findBy y findAllBy es que el primero slo devolver la primera instancia que cumpla la condicin de bsqueda, mientras que el segundo devolver una lista con todos los resultados que correspondan. Veamos algunos ejemplos: def d def l @@5uscar un departamento por su nombre1 d 7 :epartamento.find5(Bombre(G"istemasG) @@5uscar todos los departamentos segUn un patrn1 l 7 :epartamento.findAll5(Codigo#iHe(G> QG) @@5uscar departamentos antiguos l 7 :epartamento.findAll5(4echaCreacion#ess2han(fech) @N 777 Mtodos introducidos en Grails 1.2 777N@

@@ :epartamentos con es2ecnico a trueI por cdigo. l 7 :epartamento.findAll s!ecnico5(Codigo#iHe(G> QG) @@ :epartamentos con es2ecnico a falsoI por fecha. l 7 :epartamento.findAll"ot s!ecnico5(4echaCreacion(..) La estructura del nombre de los mtodos dinmicos ser: 8Clase9.#ind$%8Cropiedad98Comparador9(8'alor9) adems, se pueden encadenar varias comparaciones con And y *r: @@2odos los departamentos cu(o cdigo empiece por > @@( su nombre empiece por " def lista 7 :epartamento .find5(Codigo#iHeAndBombre#iHe(G> QGIG"QG) Los comparadores que podemos utilizar son: Pn#ist el valor debe estar entre los de la lista que proporcionamos. #ess2han el valor debe ser menor que el que proporcionamos.

Pgina 77

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

#ess2hanE%uals el valor debe ser menor o igual. +reater2han el valor debe ser mayor +reater2hanE%uals el valor debe ser mayor o igual. #iHe Equivalente a un LIKE de SQL. P#iHe LIKE sin distinguir maysculas y minsculas. BotE%ual El valor debe ser distinto al que proporcionamos. 5et&een El valor debe estar entre los dos que proporcionamos. PsBotBull El valor no debe ser nulo. PsBull El valor debe ser nulo.

Las consultas mediante dynamic finders tambin pueden paginarse y ordenarse, proporcionando como ltimo parmetro un Map con los valores correspondientes de ma3, offset, sort y order: def deps 7 :epartamento.findAll5(Bombre(G"istemasGI8ma31 >I offset1=I sort1id order1GdescG9)

Criteria
Los dynamic finders son un sistema muy potente para realizar consultas bsicas sobre nuestro modelo de datos, pero no permite hacer bsquedas avanzadas que incluyen muchos campos y comparaciones complejas. Para ese tipo de consultas es mucho ms recomendable construir nuestras consultas mediante Criteria, una sintaxis avanzada que se basa en un Builderde Groovyy la CriteriaAPI de Hibernate : def c 7 :epartamento.createCriteria() def resulado 7 c6 bet&een(AfechaCreacionAIno& - K>Ino& and 6 liHe(AcdigoAIA> QA) ; ma3.esults( =) order(AnombreAIAascA) ;

Tienes ms informacin sobre esta tcnica, y ejemplos de cdigo en http://grails.org/doc/1.1/guide/5.%20Object%20Relational%20Mapping


Pgina 78

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

%20(GORM).html#5.4.2 Criteria

NamedQueries
A partir de Grails 1.2, GORM soporta el concepto de Named Queries, o consultas con nombre. Se trata de definir en la misma clase persistente las consultas ms habituales que vamos a realizar sobre ella, de manera que podamos usarla por su nombre en lugar de escribir siempre el cdigo: class :epartamento 6 "tring nombre 5oolean especial static namedVueries 7 6 especiales6 e% GespecialGI true ; ;

; Una vez definida la consulta, podramos utilizarla en cualquier parte de la aplicacin, por ejemplo: def departamentosEsp 7 :epartamento.especiales.list() def num 7 :epartamento.especiales.count() def dEspCaginado 7 :epartamento.especiales.list( ma31 >>I offset1 > )

HibernateHQL
Finalmente, podemos utilizar el lenguaje de consulta de Hibernate, HQL, para definir nuestras consultas: def deps 7 :epartamento.findAll( Afrom :epartamento as d &here d.nombre liHe G"QGA) @@Con parTmetros1 deps 7 :epartamento.findAll( Afrom :epartamento as d &here d.id7WAI8X9) @@)ultil$nea1 deps 7 :epartamento.findAll(AY from :epartamento as d Y &here d.nombre liHe W *r d.codigo 7 WAI8G"QGIG> KG9) @@Con paginacin1 deps 7 :epartamento.findAll( Afrom :epartamento &here id > WAI
Pgina 79

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

8X9I 8ma31 >Ioffset1K=9)

Puedes encontrar una completa referencia de HQL en la web de Hibernate: http://www.hibernate.org.

Conceptosavanzadosde GORM
Con lo visto hasta este punto ya tienes todas las herramientas necesarias para construir la mayora de los modelos de datos que te puedas encontrar. Veamos ahora un par de conceptos avanzados que te interesa conocer: la posibilidad de capturar eventos lanzados por GORM cuando manipula tus objetos persistentes, y las capacidades de Hibernate para usar distintos tipos de cach de entidades.

Eventosde persistencia
GORM permite registrar auditores de eventos para reaccionar cuando se manipulan los datos. Los eventos soportados con: beforePnsert justo antes de insertar un objeto en nuestra base de datos. before0pdate justo antes de actualizar un registro. before:elete justo antes de eliminar un registro. afterPnsert justo despus de insertar un registro. after0pdate justo despus de actualizar un registro after:elete justo despus de eliminar el registro on#oad ejecutado cuando cargamos el objeto de la base de datos.

Podemos capturar esos eventos en nuestras clases de entidad para actuar en los momentos importantes de su ciclo de vida: Class Cersona6 :ate fechaAlta :ate fecha0ltima)odificacion def beforePnsert 7 6 fechaAlta 7 ne& :ate() ; def before0pdate 7 6 fecha0ltima)odificacion 7 ne& :ate()
Pgina 80

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; ;

Polticade cach
Cuando utilizamos un sistema de traduccin objeto-relacional (ORM,o Object-Relational Mapping ) como Hibernate, es de vital importancia usar una buena poltica de cach para conseguir un buen rendimiento de nuestra aplicacin. Por eso, aunque GORM se encarga de configurar automticamente este aspecto, conviene que conozcamos lo que ocurre detrs del teln y sepamos modificar el comportamiento por defecto si fuera necesario.

Sobrelas cachsde objetos


Hibernate, como cualquier otro ORM, gestiona la traduccin entre filas en tablas de una base de datos relacional y objetos en memoria, as que cada vez que queremos leer un objeto de la base de datos, debe realizar los siguientes pasos: Traducir la consulta del lenguaje Hibernate (HQL) al de la base de datos (SQL). Lanzar la consulta contra la base de datos mediante JDBC. Si la consulta devuelve resultados, para cada fila del ResultSet tiene que: Crear una instancia de la clase correspondiente. Poblar sus propiedades con los campos de la fila actual, haciendo las traducciones de tipo que sean necesarias. Si existen relaciones con otras clases, cargar los objetos de la base de datos repitiendo el proceso actual para cada uno, y poblar la coleccin, o propiedad correspondiente.

Como podrs imaginar, este proceso es bastante exigente en trminos de memoria y CPU, as que nos interesa mantener en memoria (cachear ) algunos de los datos ledos o generados para poderlos reutilizar entre peticiones. Existen tres niveles distintos de cach segn el mbito en que se apliquen: Cachde nivel 1 Consiste en que los objetos que se crean en lecturas desde la base de datos se recuerdan y comparten para la sesin actual. Si necesitamos realizar dos operaciones con el mismo objeto a lo largo de una sesin, la lectura desde la base de datos slo se realizar la primera, y en la segunda se volver a utilizar el mismo objeto. Este es un comportamiento automtico de Hibernate y no es necesario activarlo. Cachde nivel 2 Consiste en recordar todos los objetos que se crean para las distintas sesiones activas. Esto quiere decir que si un usuario carga una entidad particular, sta se mantendr en memoria durante un tiempo para que lecturas posteriores (incluso desde otras sesiones) no necesiten ir de nuevo contra la base de datos. El beneficio que se obtiene en rendimiento es grande, pero conlleva un
Pgina 81

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

precio alto, pues hay que coordinar el acceso de las distintas sesiones a los objetos, en especial si desplegamos nuestra aplicacin en un clster de servidores. Cachde consultas Consiste en recordar los datos crudos devueltos en las consultas a la base de datos. Este nivel es poco til en la mayora de los casos, pero resulta muy beneficioso si realizamos consultas complejas, por ejemplo para informes con datos calculados o que impliquen a varias tablas.

ConfigurandoHibernate
Podemos configurar el uso de cach de nivel 2 as como la cach de consultas (recuerda que la cach de nivel 1 est activada por defecto) en el archivo grailsapp@conf@:ata"ource.groov(: hibernate 6 cache.useRsecondRlevelRcache7true cache.useR%uer(Rcache7true cache.providerRclass7Gorg.hibernate.cache.EhCacheCrov iderG ; El ltimo valor se refiere a la implementacin que Clstering: en este contexto, nos referimos a deseamos utilizar para almacenar los datos la posibilidad de replicar los datos cacheados cacheados. Dado que se trata de un problema entre distintos nodos de un clster de servidores. complicado de resolver, y que puede enfocarse desde distintos puntos de vista, Hibernate permite utilizar distintas estrategias en funcin de nuestros requerimientos: EHCache(org.hibernate.cache.EhCacheProvider) Se trata de una cach muy rpida y sencilla de utilizar, que permite almacenar los datos en memoria o en archivos, aunque no soporta clustering . OSCache(org.hibernate.cache.OSCacheProvider) Permite utilizar Open Symphony Cache, un producto muy potente y flexible con soporte para clustering va JavaGroups o JMS. SwarmCache(org.hibernate.cache.SwarmCacheProvider) Una cach pensada especficamente para aplicaciones desplegadas en clster que realizan ms operaciones de lectura que de escritura. JBossTreeCache(org.hibernate.cache.TreeCacheProvider) Una cach muy potente, con soporte de clstering y transaccional. Como ves, la eleccin depende de los requisitos de nuestra aplicacin, sobre todo respecto al despliegue en clsters de servidores. Por defecto Hibernate utiliza EHCache , que funciona correctamente en la mayora de las situaciones.

Pgina 82

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Definir la polticade cachen cadaclase


Como hemos visto en ste mismo captulo, podemos incluir un bloque esttico mapping en nuestras entidades para controlar la forma en que Hibernate traduce nuestros objetos a tablas de la base de datos. Tambin podemos utilizar ese bloque para controlar la poltica de cach de nuestros objetos persistentes: class Cersona 6 @@. . . static mapping 7 6 @@obligamos a leer cada ve/ de la 5.:. cache1 false ; ;

Usarlas cachsfuerade GORM


El uso de cachs presenta ventajas no slo para el acceso a bases de datos, sino en cualquier situacin en la que el proceso de obtencin o generacin de informacin sea caro en trminos de CPU. Imagina por ejemplo una aplicacin en la que se tienen que obtener datos mediante una conexin a un servicio web remoto. Si el dato que vamos a necesitar cambia con poca frecuencia no tiene sentido que para cada peticin de nuestros usuarios hagamos una peticin al servidor externo. En este tipo de situaciones se obtiene un gran beneficio del uso de cachs. La librera EHCache no es para uso exclusivo de Hibernate, sino que podemos utilizarla en nuestra ampliacin gracias al contenedor Spring. Para ello simplemente tenemos que declarar un bean de tipo org.springframe&orH.cache.ehcache.EhCache4actor(5ean en el archivo grails-app@conf@spring@resources.groov(: beans 7 6 i&'ache( org.springframe&orH.cache.ehcache.EhCache4actor(5ean )6 time2o#ive 7 K>> @@K> min. ; ; Hemos asignado el nombre i&Cache al bean, y ese es el nombre con el que podremos acceder a l desde nuestra aplicacin: class E,emploController 6 @@in(eccin por nombre1 def i&Cache def servicio.emoto

Pgina 83

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@@... def accion 7 6 def dato 7 i&Cache.get(Gclave-datoG)W.value if(Zdato)6 dato 7 servicio.emoto.get:ato() i&Cache.put ne& Element(Gclave-datoGIdato) ; return dato ;

Al declarar una variable de clase con el mismo nombre que el bean, Grails ha inyectado el servicio automticamente, de manera que podemos utilizarlo en nuestras acciones, igual que hace con los servicios. La mayora de las libreras de cach se comportan como Maps: guardamos objetos asociados a una clave para poder recuperarlos ms tarde, y configuramos la cach para que borre automticamente aquellos datos que se consulten con menos frecuencia para controlar el uso de memoria. Esta tcnica no es exclusiva de las cachs: podemos registrar en Spring cualquier bean que necesitemos utilizar en nuestra aplicacin declarndolo en el archivo resources.groov(, y lo tendremos disponible en todos nuestros artefactos.

Pgina 84

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

8. Contro!ador s

Pgina 85

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

En una aplicacin MVC, los controladores son los componentes responsables de recibir las rdenes del usuario, gestionar la ejecucin de la lgica de negocio y despus actualizar la vista para mostrar al usuario el estado en que ha quedado el modelo de datos. En trminos de aplicaciones web, los controladores son por tanto los responsables de interceptar las peticiones HTTP del navegador y generar la respuesta correspondiente (que puede ser html, xml, json, o cualquier otro formato), ya sea en el propio controlador o delegando el trabajo en una vista GSP (las veremos en el captulo 10). La convencin utilizada en Grails es que un controlador es cualquier clase que se encuentre en la carpeta grails-app@controllers de nuestro proyecto y cuyo nombre termine por Controller. Para cada peticin HTTP, Grails determinar el controlador que debe invocar en funcin de las reglas fijadas en grails-app@conf@0rl)appings.groov(, crear una instancia de la clase elegida e invocar la accin correspondiente. La configuracin por defecto consiste en definir URIs con este formato: @8controlador9@8accin9@8id9 donde: 8controlador9 es la primera parte del nombre de nuestro controlador (eliminando el sufijo Controller) 8accin9 es la closure a ejecutar 8id9 el tercer fragmento de la uri estar disponible como params.id

Para ilustrar la creacin de controladores, vamos a construir en nuestra aplicacin uno que nos permita obtener la lista de usuarios registrados en distintos formatos. Para crear un controlador debemos invocar el comando: grails create-controller persona El resultado es que Grails genera la clase grailsapp@controllers@CersonaController.groov(. Dentro de esa clase, tendremos que crear una closure para cada accin que tenga que ejecutar este controlador: import grails.converters.N class CersonaController 6 def lista 6 def l 7 Cersona.list() 8lista1l9 ;
Pgina 86

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def lista[ml 7 6 def l 7 Cersona.list() render l as [)# ; def lista-son 7 6 def l 7 Cersona.list() render l as -"*B ;

En este controlador hemos definido tres acciones. Las tres generan un listado de entidades Persona en la base de datos, invocando a Persona.list(), pero en tres formatos distintos: @persona@lista Esta accin devuelve un Recuerda que en Groovy la palabra reservada return es opcional, y los mtodos y closures Map con la lista de instancias asociada a la clave 'lista'. La convencin dice que en Grails si devuelven el valor de la ltima sentencia. una accin devuelve un Map, ste ser el modelo a representar en la vista por defecto, que ser la que se encuentre en grails-app@vie&s@8controlador9@8accin9.gsp. En este caso sera grails-app@vie&s@persona@lista.gsp. Veremos ms sobre esto en el captulo siguiente. @persona@lista[ml Esta accin no devuelve nada, sino que invoca al mtodo render, que veremos ms adelante, y que permite generar la respuesta directamente en el controlador. En este caso usamos un converter de Grails que es capaz de representar la lista de entidades Cersona en xml. El resultado sera algo parecido a esto: Elist> Epersona id7A A> Enombre>CacoE@nombre> Eapellidos>+me/E@apellidos> E@persona> Epersona id7AKA> Enombre>-osSE@nombre> Eapellidos>"anche/E@apellidos> E@persona> ... E@list> @persona@lista-son La ltima accin mostrar el listado de entidades Persona en formato JSON (JavaScript Object Notation), un formato ligero para el intercambio de datos muy utilizado principalmente en contextos AJAX: 8 6AidA1 I AclassA1ACersonaAI AnombreA1ACacoAI
Pgina 87

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

AapellidosA1A+me/A; 6AidA1KI AclassA1ACersonaAI AnombreA1A-osSAI AapellidosA1A"anche/A; ... 9 Veamos ahora con ms profundidad las posibilidades que presentan los controladores.

mbitos
Dentro de un controlador disponemos de una serie de objetos implcitos que podemos utilizar para almacenar datos. Se trata de Maps que corresponden a los distintos mbitos que podemos encontrar normalmente en cualquier aplicacin web: servletConte3t contiene los datos del mbito de aplicacin. Cualquier valor que almacenemos en este objeto estar disponible globalmente, desde cualquier controlador o accin. session permite asociar un estado a cada usuario, normalmente mediante el envo de cookies http. Los datos que guardemos en este mbito sern visibles nicamente para el usuario, mientras su sesin est activa. re%uest Los valores almacenados en este objeto sern visibles durante la ejecucin de la solicitud actual. params contiene todos los parmetros de la peticin actual, tanto los de la url como los del formulario si lo hubiera. Se trata de un mapa mutable, de manera que podemos aadir nuevos valores si fuera necesario, o modificar los existentes. flash este mbito es un almacn temporal para atributos que necesitaremos durante la ejecucin de la peticin actual y la siguiente, y que sern borrados despus. La ventaja de este mbito es que podemos guardar datos que sern visibles si devolvemos al usuario un cdigo de redireccin http (con lo que se produce otra peticin HTTP, de manera que no nos sirve el objeto re%uest), y luego se borrarn.

Por ejemplo: import grails.converters.N class CersonaController 6 def ver[ml 7 6 var p 7 Cersona.find5(Bombre(params.nom) if(p)6 render p as [)# ;
Pgina 88

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

else6 #lash.message 7 Ano encontradoA redirect(action1inde3) ; ; El controlador anterior recibira una URI como la siguiente: @persona@ver[mlWnom74rancisco y devolvera el usuario con el nombre indicado como xml, o bien redirigira a la accin index colocando un mensaje de error en el mbito flash en caso de que no existiera ningn usuario con ese nombre. Desde la versin 1.2 podemos acceder a los parmetros de entrada mediante mtodos de conversin de tipo que los convierten automticamente al tipo de dato deseado. Por ejemplo: def ma3 7 params.int(Gma3G) de esta manera, la variable ma3 contendr un int, en lugar de un "tring como hasta ahora. ;

El mtodorender,a fondo
Como hemos comentado, si la accin que se est ejecutando no incluye ninguna llamada al mtodo render, Grails tratar de localizar la vista predeterminada para esa accin, en el archivo grails-app@vie&s@8controlador9@8accin9. Si la accin devuelve un Map con el modelo a mostrar, los campos definidos en dicho Map estarn accesibles en la vista GSP como variables locales. Si la accin no devuelve nada, entonces la GSP tendr acceso a las variables locales definidas en el propio Controlador (recuerda que se crea una instancia del Controlador para cada peticin). Esta convencin es til en ciertas situaciones, pero no en la mayora de los casos. Lo ms habitual es que necesitemos ms control sobre la respuesta que enviamos al navegador, en cuyo caso podemos usar el mtodo render. Se trata de un mtodo muy verstil para enviar respuestas al cliente, ya que acepta un gran nmero de parmetros y permite diferentes usos. Los parmetros que podemos pasarle son: te3t la respuesta que queremos enviar, en texto plano. builder un builder para generar la respuesta (ms sobre los builders en el APNDICE A. vie& La vista que queremos procesar para generar la respuesta.

Pgina 89

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

template La plantilla que queremos procesar (ms sobre plantillas en el captulo 10). plugin el plugin en el que buscar la plantilla, si no pertenece a nuestra aplicacin. bean un objeto con los datos para generar la respuesta. var el nombre de la variable con la que accederemos al bean. Si no se proporciona el nombre por defecto ser "it". model Un Map con el modelo para usar en la vista. collection Coleccin para procesar una plantilla con cada elemento. content2(pe el tipo mime de la respuesta. encoding El juego de caracteres para la respuesta. converter Un objeto grails.converters.* para generar la respuesta. Todos los parmetros que recibe render son opcionales, y en funcin de los que le proporcionemos el funcionamiento ser diferente. Veamos algunos ejemplos para entenderlo mejor: @@Enviar te3to1 render Arespuesta simpleA @@especificar el tipo mime ( codificacin1 render( te3t1AEerror>Fubo un errorE@error>AI content2(pe1Ate3t@3mlAI encoding1A024-!A ) @@procesar una plantilla con un modelo1 render( template1GlistadoGI model18lista1Cersona.list()9 ) @@o con una coleccin1 render( template1GlistadoGI collection18p IpKIp<9 ) @@o con un ob,eto1 render( template1GpersonaGI bean1Cersona.get(K<)I var1GpG ) @@procesar una vista con un modelo1 render(
Pgina 90

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

) @@o con el Controlador como modelo1 render(vie&1GpersonaG) @@generar marcado usando un 5uilder (o,o con las llaves)1 render 6 div(id1Gid:ivGIGContenido del :P'G) ; render(content2(pe1Gte3t@3mlG) 6 listado 6 Cersona.list().each 6 persona( nombre1it.nombreI apellidos1it.apellidos ) ; ; ; @@generar -"*B1 render(content2(pe1Gte3t@,sonG) 6 persona(nombre1p.nombreIapellido1p.apellido) ; @@generar [)# ( -"*B automTticamente1 import grails.converters.N render Cersona.list(params) as [)# render Cersona.get(params.id) as -"*B

vie&1GlistadoGI model18lista1Cersona.list()9

Encadenaracciones
Hay ocasiones en las que el resultado de una accin debe ser la ejecucin de otra accin. En estos casos podemos usar dos mtodos distintos en funcin del efecto que busquemos: redirect termina la ejecucin de la solicitud actual enviando al cliente un cdigo de redireccin HTTP junto con una nueva URL que invocar. El navegador llamar de forma automtica a esta nueva direccin como resultado. Es importante tener en cuenta que cuando procesemos la segunda peticin no tendremos acceso al mbito re%uest de la primera, de manera que los datos que queramos conservar debern guardarse en el mbito flash. Veamos algunos ejemplos: @@.edirigir a otra accin de este controlador1 redirect(action1GotraAccionG)

Pgina 91

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@@.edirigir a otra accin en otro controlador1 redirect(controller1GaccessGIaction1GloginG) @@Caso de parTmetros1 redirect(action1GotraAccionGIparams18p 1Gv GI...9 @@Casar los parTmetros de esta peticin1 redirect(action1GotraGIparams1params) @@.edirigir a una 0.#1 redirect(url1Ghttp1@@&&&.imagina&orHs.comG) @@.edirigir a una 0.P1 redirect(uri1G@condiciones.uso.htmlG) chain Si necesitamos que el modelo se mantenga entre la primera accin y la segunda podemos utilizar el mtodo chain1 class E,emploController 6 def accion 7 6 def m 7 8GunoG1 9 chain(action1actionKImodel1m) ; def accionK 7 6 8GdosG1K9 ; ; @@El modelo resultante serT 8GunoG1 IGdosG1K9

Interceptors
En el captulo 13 hablaremos sobre los Filtros , componentes que controlan el acceso de los usuarios a nuestra aplicacin al estilo de los Filtros JavaEE. Pero en Grails existe adems otro sistema para lograr el mismo efecto definindolo directamente en el Controlador: los Interceptors . Se trata de closures con un nombre especfico que Grails ejecutar, si estn presentes, antes y/o despus de llamar a la accin solicitada por el navegador: class CersonaController 6 def beforePnterceptor 7 6 println Aprocesando1 $6action0ri;A ; def afterPnterceptor 7 6model -> println Acompletado1 $6action0ri;A println A)odelo generado1 $6model;A ; ... ;

Pgina 92

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Si el beforePnterceptor devuelve false, la ejecucin se detendr antes de llegar a la accin. Tambin podemos especificar para qu acciones debe ejecutarse un interceptor, y definir la lgica en un mtodo privado: class CersonaController 6 def beforePnterceptor 7 8 action1this.\authI e3cept18GloginGIGregisterG9 9 private auth()6 if(Zsession.user)6 redirect(action1GloginG) return false] ; ; ; En este ejemplo, hemos definido un beforePnterceptor que captura todas las acciones, excepto login y register, e invoca el mtodo auth (privado, para que no sea expuesto como una accin por el controlador) que comprobar si el usuario est identificado antes de continuar procesando la peticin.

Procesardatosde entrada
Los controladores Grails presentan numerosas funcionalidades para procesar los datos de entrada, algunas de las cuales nos evitarn un montn de trabajo repetitivo al realizar conversiones de tipo automticas y asignacin de datos de entrada a variables en funcin de su nombre (data binding). A continuacin veremos algunas de estas potentes herramientas, y mostraremos ejemplos de uso de cada una.

Data Binding
Grails utiliza las capacidades de Spring para procesar los datos de entrada, y asociarlos automticamente a los objetos de nuestro modelo. Para conseguir este efecto, podemos utilizar el constructor implcito que tienen todas las clases de entidad: def save 7 6 def p 7 ne& Cersona(params) p.save() ;

Pgina 93

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El constructor recibe como argumento el Map con los parmetros de la peticin. Para cada clave del mapa, Grails buscar en el objeto una propiedad con el mismo nombre, y asignar el valor asociado en el mapa a dicha propiedad. Si es necesario, se convertir automticamente el tipo del parmetro (String) al tipo requerido. Tambin podemos realizar este proceso para instancias existentes mediante la propiedad properties: def save 7 6 def p 7 Cersona.get(params.id) p.properties 7 params p.save() ; Al usar este sistema, podramos invocar la accin de esta manera: @persona@save@KWnombre7Caco\apellidos7+me/ Y no tendramos que asociar manualmente cada parmetro a la propiedad correspondiente del objeto Cersona.

Si la conversin automtica de datos produjese errores, stos quedaran almacenados en la propiedad errors de la entidad, y el mtodo hasErrors() devolvera true. De esta manera, el cdigo completo de la accin quedara as: class CersonaController 6 def save 7 6 def p 7 Cersona.get(params.id) p.properties 7 params if(p.hasErrors())6 @@procesar la lista de errores. ; else6 @@la operacin tuvo S3ito. ; ; ; Si nuestra clase de entidad tiene relaciones con otras entidades, tambin podemos usar data binding: @persona@save@<Wdepartamento.id7=

Recibirficheros

Pgina 94

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Para la gestin de subidas de archivos al servidor, Grails utiliza - una vez ms las bondades de Spring, mediante la interfaz org.springframe&orH.&eb.multipart.)ultipartFttp"ervlet.e%uest. Para enviar ficheros al servidor tenemos que crear el formulario correspondiente en nuestra vista GSP: Eg1form action7AsaveA method7ApostA enct(pe7Amultipart@form-dataA> Einput t(pe7AfileA name7AfotoA @> Einput t(pe7AsubmitA value7AenviarA @> E@g1form> En nuestro controlador, el archivo estar disponible mediante un objeto que implementar la interfaz org.springframe&orH.&eb.multipart.)ultipart4ile, que nos proporciona los siguientes mtodos: get5(tes() - devuelve un array de bytes con el contenido del archivo. getcontent2(pe() - devuelve el tipo mime del archivo. getPnput"tream() - devuelve un InputStream para leer el contenido del archivo. getBame() - Devuelve el nombre del campo file del formulario. get*riginal4ileBame() - Devuelve el nombre original del archivo, tal como se llamaba en el ordenador del cliente. get"i/e() - devuelve el tamao del archivo en bytes. isEmpt(() - devuelve true si el archivo est vaco o no se recibi ninguno. transfer2o(4ile dest) copia el contenido del archivo al archivo proporcionado. Es importante tener en cuenta que los datos se almacenarn en un archivotemporalque ser borradoautomticamenteal terminar de procesar la peticin, as que si quieres mantener el archivo debes copiarlo a otro sitio invocando transfer2o. Podemos recibir una peticin de este tipo de dos maneras posibles: Si el contenido del archivo debe guardarse en una propiedad de una entidad (por ejemplo, la foto del perfil de usuario), podemos usar el data binding: class Cersona 6 "tring nombre "tring apellidos b(te89 foto @N
*bserva %ue la propiedad foto es de tipo b(te89I ( %ue el nombre coincide con el nombre del campo file del formulario.

Pgina 95

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

N@ ; class CersonaController 6 def save 7 6 def p 7 ne& Cersona(params) ; ; En el caso ms general, podemos acceder al archivo recibido directamente: def save 7 6 def archivo 7 re%uest.get4ile(GfotoG) if(Zarchivo.empt()6 archivo.transfer2o(ne& 4ile(G....G)) render AArchivo guardadoA ; else6 flash.message 7 Ano se recibi archivoA redirect(action1GeditG) ; ;

Evitarel doblepost
Como sabes, una aplicacin web se basa en que el usuario enva datos al servidor y recibe una nueva pgina como respuesta. En nuestro caso, quien recibe las peticiones es el Controlador asociado a la URL invocada. Pero este paradigma, basado en el protocolo HTTP, tiene un riesgo: si el usuario pulsa el botn de enviar de un formulario, y la respuesta tarda ms tiempo en generarse del que el usuario est dispuesto a esperar, es posible que ste vuelva a darle al botn de enviar pensando que "la otra vez no lleg al servidor". En este caso tenemos el mismo formulario enviado dos veces al servidor, con un intervalo de algunos segundos, lo cual puede dar lugar a inconsistencias en el comportamiento de la aplicacin y en los datos almacenados. Existen varias formas de evitar esto, la ms sencilla es des habilitar por javascript el botn de enviar cuando el usuario lo pulsa la primera vez: Einput t(pe7^submit^ name7^s^ value7^Enviar^ onclicH7^this.disabled7true^ @> Pero sin duda las ms robustas son aquellas que involucran al servidor en este
Pgina 96

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

problema. Grails permite usar tokens en el envo de formularios de manera que cuando un formulario se est procesando se almacena el valor del token asociado en la sesin del usuario, y no se permite el procesamiento del mismo token hasta que termine la primera ejecucin. Para activar este comportamiento tenemos que usar el atributo use2oHen en la etiqueta Eg1form ...>: Eg1form use2oHen7AtrueA action7AsaveA ...> De esta manera, la etiqueta form generar un cdigo similar a ste: Eform action7A@almanac@usuario@saveA method7ApostA > Einput t(pe7AhiddenA name7Aorg.codehaus.groov(.grails."OBCF.*BP_E.R2*`EBA value7AefK!=dDM-cbKa-M <d-!bdM-<MD>D da>?b<A id7Aorg.codehaus.groov(.grails."OBCF.*BP_E.R2*`EBA @> Einput t(pe7AhiddenA name7Aorg.codehaus.groov(.grails."OBCF.*BP_E.R0.PA value7A@almanac@usuario@createA id7Aorg.codehaus.groov(.grails."OBCF.*BP_E.R0.PA @> ... en el que se definen dos campos ocultos para controlar el envo del formulario al servidor. Al enviar este formulario pueden pasar dos cosas: Si queremos, podemos tratar el token explcitamente en nuestra accin: def save 7 6 &ith4orm 6 @@4ormulario enviado correctamente. ;.invalid.e%uest 6 @@4ormulario enviado por duplicado. ; ; O si no lo hacemos, el comportamiento por defecto es que si Grails detecta un doble post la segunda invocacin ser redirigida automticamente de nuevo a la vista del formulario, y el token repetido ser guardado en el mbito flash para que podamos tratarlo en la pgina GSP: Eg1if test7A$6flash.invalid2oHen;A>
Pgina 97

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Cor favorI no pulse el botn enviar hasta %ue ha(a terminado de procesarse el formulario. E@g1if> Eg1form ...> ...

ObjetosCommand
Existen situaciones en las que necesitamos data binding o validar la informacin que llega con un formulario, pero no hay ninguna entidad involucrada en el proceso para poder usarlos. En estos casos Grails nos propone el uso de "Command Objects" (objetos comando), que se pueblan automticamente con los datos que llegan en la solicitud. Normalmente se definen en el mismo archivo de cdigo fuente que el controlador: class CersonaController 6 def login 7 6#oginCommand cmd -> if(cmd.hasErrors())6 redirect(action1Glogin4ormG) ; else6 session.user 7 Cersona .find5(0serBame(cmd.userBame) redirect(controller1GhomeG) ; ; ; class #oginCommand 6 "tring userBame "tring userCass static constraints 7 6 userBame(blanH1falseImin"i/e1D) userCass(blanH1falseImin"i/e1D) ; ; Como ves, podemos definir restricciones (constraints) como si se tratase de una clase de entidad. En la accin del controlador, tenemos que declarar el parmetro con el tipo del objeto command, y Grails se encargar de poblar las propiedades con los parmetros de la solicitud de forma automtica. Igual que las entidades, los objetos command tienen una propiedad errors y un mtodo hasErrors() que podemos utilizar para validar la entrada.

Pgina 98

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

9. % r;icios

Pgina 99

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

En una aplicacin MVC, la capa de servicios es la responsable de implementar la lgica de negocio de nuestra aplicacin. Es muy importante entender el significado y la utilidad de esta capa para poder desarrollar aplicaciones fciles de mantener y evolucionar.

Por qu deberanimportartelos servicios


El fallo nmerounoque cometemosal aplicarel patrnMVCcuandosomosprincipianteses colocardemasiadocdigoen la capade Control . Al hacerlo, estamos asegurndonos una fase de mantenimiento complicada y comprando todos los tickets para la lotera del cdigo spaghetti. Incluso los casos de uso que en una implementacin inicial parecen sencillos pueden, a medida que crece la aplicacin, convertirse en autnticas cajas negras que nadie se atreve a tocar porque el cdigo es incomprensible. El siguiente diagrama muestra el flujo recomendado para un caso de uso tpico:

El usuario pulsa un link en la vista, o un botn Submit de un formulario. La solicitud llega a la accin correspondiente el controlador, segn lo configurado en el mapeo de URLs. El controlador invoca al servicio encargado de la implementacin del caso de uso. En base al resultado de la invocacin, decide cul es la prxima vista a mostrar, y solicita a la capa de presentacin que se la muestre al usuario. Al utilizar este reparto de responsabilidades conseguimos, por un lado, componentes ms pequeos y fciles de mantener, y por otro, la posibilidad de reutilizar nuestro cdigo en mayor medida.

Pgina 100

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Ok, peroques un Servicioen GRAILS?


Segn la convencin que sigue Grails, un servicio es una clase cuyo nombre termina en "ervice y que se aloja en la carpeta grails-app@services. En tiempo de ejecucin, Grails usar la magia del contenedor Spring para hacer que todas las clases que declaren una variable con el mismo nombre que el servicio tengan una instancia a su disposicin. Supongamos el siguiente escenario: tenemos una aplicacin en la que al dar de alta un usuario tenemos que configurar su cuenta con una serie de valores iniciales que dependen de varios factores relacionados con la lgica de negocio (a qu departamento pertenezca, desde qu IP acceda al servicio, si ha introducido algn cdigo especial de seguridad, o cualquier otra restriccin de este tipo). Vamos a crear un servicio que implemente ste caso de uso. Lo primero es pedir a Grails que genere el esqueleto de la case para nosotros: grails create-service usuario Como respuesta a este comando, Grails crea la clase grailsapp@services@0suario"ervice.groov(: class 0suario"ervice 6 boolean transactional 7 true def service)ethod() 6 ; ; Como ves, el nuevo servicio tiene una propiedad que indica si se trata o no de un servicio transaccional. Si transactional vale true, entoncestodaslas llamadasa mtodosde nuestroserviciose encerrarnen una transaccin,producindoseun rollback automticosi durantela ejecucinsaltaseuna excepcin . Vamos a sustituir el mtodo de ejemplo service)ethod por nuestro mtodo de alta de usuario, que recibir el mapa con los parmetros de la peticin y devolver una instancia de Persona: Cersona alta0suario(params)6 def p 7 ne& Cersona(params) @@ . validar datos de entrada if(p.validate())6 @@aplicar reglas a p @@. . . p.save() ;
Pgina 101

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

return p

Lo primero que hacemos es, asumiendo que params trae los campos del formulario de alta desde la vista, crear la entidad Persona para esos parmetros, e invocar al mtodo validate sobre ella para que se apliquen todas las reglas de validacin definidas en las constraints de Persona. Si validate devuelve falso, habr errores en la propiedad errors de p, y como no entramos en el bloque if, el servicio devuelve la entidad sin guardar en la base de datos y con todos los mensajes de error para que el controlador decida qu hacer. En caso de que validate devuelva verdadero, aplicaremos las reglas de negocio pertinentes y guardaremos la instancia en la base de datos mediante una llamada al mtodo save. El controlador tendr por tanto este aspecto: class 0suarioController 6 de# usuario(er)ice @@ . . . otra acciones def save 7 6 def p 7 usuario"ervice.alta0suario(params) if(p.hasErrors())6 @@tratar errores ; else6 flash.message 7 G0suario registrado.G redirect(action1Gsho&GIid1p.id) ; ;

Como ves, en el controlador declaramos una variable con el mismo nombre que la clase 0suario"ervice, salvo por la primera letra minscula. sta es la convencin a seguir para que Grails inyecte automticamente una instancia del servicio en nuestro controlador, con lo que no debemos preocuparnos por su ciclo de vida.

Polticade creacinde instancias


Como hemos visto, Grails controla el ciclo de vida de nuestros servicios, decidiendo cundo se crean instancias de los mismos. Por defecto, todos los servicios son singleton: slo existe una instancia de la clase que se inyecta en todos los artefactos que declaren la variable correspondiente. Este criterio es apropiado para la mayora de las situaciones, pero tiene un inconveniente: no podemos guardar informacin que sea privada de una peticin en el servicio porque todos los controladores veran la misma instancia y por tanto el
Pgina 102

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

mismo valor. Podemos modificar este comportamiento declarando una variable scope en el servicio con alguno de estos valores: protot(pe cada vez que se inyecta el servicio en otro artefacto se crea una nueva instancia. re%uest se crea una nueva instancia para cada solicitud HTTP. flash cada instancia estar accesible para la solicitud HTTP actual y para la siguiente. flo& cuando declaramos el servicio en un web flow (ver captulo 11), se crear una instancia nueva en cada flujo. conversation cuando declaramos el servicio en un web flow, la instancia ser visible para el flujo actual y todos sus sub-flujos (conversacin) session Se crear una instancia nueva del servicio para cada sesin de usuario. singleton (valor por defecto) slo existe una instancia del servicio.

Por tanto, si por ejemplo queremos que un exista una instancia de un servicio particular para cada sesin de usuario, tendremos que declararlo as: class 0noCor0suario"ervice 6 static scope 7 GsessionG @@. . . ;

Mtodostransaccionales
Desde la versin 1.2, los servicios Grails permiten usar anotaciones en los mtodos para marcarlos como transaccionales. De esta manera podemos establecer distintos niveles de proteccin en cada mtodo: import org.springframe&orH.transaction.annotation.N class 0suarios"ervice 6 J2ransactional def registra0suario()6 @@ "e e,ecuta en una transaccin. ; J2ransactional(readonl(7true) def buscar0suarios() 6 @@ "e e,ecuta en una transaccin de slo @@ lectura. ;

Pgina 103

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

J2ransactional(timeout7 >>>>) def registraEn"ervicio.emoto()6 @@ "i no ha terminado en >GG la transaccin @@ habrT fallado. ; J2ransactional(isolation7Psolation."E.PA#P_A5#E) def modifica0suario()6 @@ "e evitarT la visibilidad de cual%uier @@ dato generado hasta %ue la transaccin @@ estS completa. ;

Tienes ms informacin sobre la anotacin Transactional en la documentacin de Spring.

Pgina 104

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

10. @istas4 "roo;= % r; r Pag s

Pgina 105

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Dentro del patrn MVC, la vista es la responsable de mostrar al usuario el estado actual del modelo de datos, y las acciones a su disposicin para que elija lo que desea hacer a continuacin. Grails incluye la tecnologa GSP (Groovy Server Pages), inspirada en las pginas JSP pero simplificando enormemente su funcionamiento. Una vista en Grails es un archivo con extensin gsp (son los nicos componentes de Grails que no son Groovy ni Java, aparte de los recursos estticos) que reside en la carpeta grails-app@vie&s de nuestro proyecto. Cuando nuestra aplicacin se est ejecutando, podemos decidir qu vista hay que procesar y enviar al cliente mediante el mtodo render de los controladores, o dejar que Grails escoja la vista por defecto, que ser aquella que tenga el mismo nombre que la accin actual y est en una carpeta con el mismo nombre que el controlador. Normalmente, una vista tiene acceso a una serie de valores que forman su modelo (no confundir con el modelo de datos de la aplicacin), y ser responsabilidad del Controlador definir tales datos para que puedan mostrarse al usuario. Desde el punto de vista formal, una pgina GSP es un archivo de texto que contiene algn tipo de marcado (normalmente html) junto con bloques dinmicos que pueden definirse de varias formas: Introduciendo cdigo Groovy entre las marcas <% y %>. Igual que con las JSP, este mtodo esta desaconsejado. Nuncaes unabuenaidea mezclarcdigofuentey marcado . Utilizando expresiones Groovy con el formato ${expresion}, que sern reemplazadas por su valor antes de enviar la respuesta al cliente. Adems de los valores definidos en el controlador, existe una serie de objetos implcitos a los que tenemos acceso desde cualquier pgina GSP: application Una referencia al contexto JavaEE (javax.servlet.ServletContext). applicationConte3t Una referencia al contexto Spring (org.springframework.context.ApplicationContext). flash El mbito flash (ver captulo sobre Controladores) grailsApplication Una referencia al objeto GrailsApplication, que nos permite acceder a otros artefactos, entre otras cosas. out Una referencia al objeto Writer sobre el que se volcar el resultado de procesar la GSP. params El Map con los parmetros de la solicitud (ver captulo sobre Controladores) re%uest Una referencia al objeto HttpServletRequest. response Una referencia al objeto HttpServlet Response session Una referencia al objeto HttpSession.
Pgina 106

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

&eb.e%uest Una referencia al objeto GrailsWebRequest, que podemos utilizar para obtener datos sobre la peticin actual no disponibles en el objeto request, como el nombre del controlador o la accin actual. Utilizando libreras de etiquetas. Como veremos a continuacin, podemos extender la funcionalidad de las GSP definiendo nuestras propias etiquetas con un sistema mucho ms simple e intuitivo que las libreras de etiquetas JSP.

EtiquetasGSP
Como hemos comentado, la forma recomendada para definir la lgica de presentacin es mediante el uso de etiquetas. Podemos definir nuestras propias libreras de etiquetas (ms sobre esto en el siguiente apartado), o utilizar el extenso conjunto de ellas que incorpora Grails. En cualquier caso, tanto las etiquetas estndar como las nuestras tendrn la siguiente sintaxis: E8ns918tag9 atrib 7Aval A atribK7AatribKA ...> EZ-- cuerpo --> E@8ns918tag9> donde: 8ns9 es el espacio de nombres (Namespace ) de la etiqueta. Las etiquetas estndar de Grails, as como las nuestras si no indicamos lo contrario, estarn en el espacio de nombres "g", por ejemplo: Eg1linH action7AloginA>Pniciar sesinE@g1@linH> 8tag9 es el nombre de la etiqueta. A continuacin haremos un repaso de las etiquetas GSP ms importantes, aunque te recuerdo que para una lista completa y actualizada puedes acudir a la documentacin oficial: http://grails.org/Documentation.

Etiquetasparamanejode variables
set Esta etiqueta puede usarse para definir variables en la pgina GSP, y definir el mbito en el que deben almacenarse. Atributos: var el nombre de la variable a crear o modificar. value el valor a almacenar en la variable. scope el mbito en el que hay que crear la variable (page, re%uest, flash, session o application).

Pgina 107

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Eg1set var7Aho(A value7A$6ne& :ate();A @>

Etiquetaslgicasy de iteracin
ifI else y elseif: Permiten la inclusin opcional de cdigo en las vistas: Eg1set var7ArolesA value7A$6session.user.roles;A @> Eg1if test7A$6roles.contains(GadminG);A> FolaI administrador. E@g1if> Eg1elseif test7A$6roles.contains(GeditorG);A> FolaI editor. E@g1elseif> Eg1else> FolaI usuario. E@g1else> each Permite iterar sobre los elementos de una coleccin: Eg1each in7A$68GCacoGIG-uanGIGCepeG9;A var7AnomA> Ep>FolaI $6nom;E@p> E@g1each> &hile Permite iterar mientras una se cumpla la condicin indicada: Eg1set var7AiA value7A$6 ;A @> Eg1&hile test7A$6i E >;A> Ep>BUmero actual1 $6i++;E@p> E@g1&hile>

Etiquetasparafiltrar colecciones
findAll Busca entre los elementos de una coleccin aquellos que satisfagan una condicin, expresada en Groovy: BUmeros pares de a .>>>1 Eul> Eg1findAll in7A$6 .. >>>;A e3pr7Ait Q K 77 >A> Eli>$6it;E@li> E@g1findAll> E@ul> grep Busca entre los elementos de una coleccin de dos formas distintas: @@5uscar ob,etos de una clase particular1 Eg1grep in7A$6personas;A filter7AConductor.classA> Ep>$6it.nombre; $6it.apellidos;E@p> E@g1grep> @@5uscar cadenas %ue cumplan una e3presin regular1 Eg1grep in7A$6personas.nombre;A
Pgina 108

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

filter7Aa@-ose.NW@A > Ep>$6it;E@p> E@g1grep>

Etiquetasparaenlazarpginasy recursos
linH Permite crear enlaces (etiquetas a de HTML) de forma lgica, que funcionarn incluso si cambiamos la configuracin de URLs de nuestra aplicacin. Veamos algunos ejemplos (ver captulo 11): Eg1linH action7Asho&A id7A A>Cersona E@g1linH>

Eg1linH controller7ApersonaA action7AlistA> #istado de personas E@g1linH> Eg1linH controller7ApersonaA action7AlistA params7A8sort1GnombreGIorder1GascG9A> #istado alfabStico de Cersonas E@g1linH> create#inH Genera una ruta para utilizar directamente en el atributo href de un enlace html, o en javascript, etc: Eg1create#inH controller7ApersonaA action7Asho&A id7A=A @> EZ-- +enera1 @persona@sho&@= --> resource Crea enlaces a recursos estticos como hojas de estilo o scripts javascript: Eg1resource dir7AcssA file7Amain.cssA @> EZ-- +enera1 @css@main.css --> include Permite empotrar la respuesta de otra accin o vista en la respuesta actual: Eg1include action7AstatusA id7A$6user.id;A @>

Etiquetasparaformularios
Grails incluye multitud de etiquetas relacionadas con formularios, para crear campos de todo tipo desde los bsicos incluidos en HTML hasta versiones ms sofisticadas como selectores de idioma: form y upload4orm Ambas crean una etiqueta form. La diferencia es que la segunda aade enct(pe7Amultipart@form-dataA para permitir el envo de
Pgina 109

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

archivos al servidor: Eg1form method7^C*"2^ name7AfA url7A8controller1GpersonaGIaction1GsaveG9A> EZ-- 4ormulario --> E@g1form> EZ-En +rails .K+ podemos utili/ar mStodos distintos a +E2 ( C*"2 en la eti%ueta form. Cor e,emploI C02 o :E#E2E permiten invocar servicios .E"2 desde formularios F2)#. --> te3t4ield Para crear campos de texto. checH5o3 Para crear campos check. radio para crear radio buttons. radio+roup para agrupar varios botones radio. hidden4ield para crear campos ocultos. select para crear listas desplegables. action"ubmit Genera un botn submit para el formulario. Permite incluir varios botones en el mismo formulario que enven los datos a deferentes urls: Eg1action"ubmit value7AEnviarA action7AsaveA @> Eg1action"ubmit value7ACancelarA action7Ainde3A @> En la mayora de los casos, los atributos que pongamos en una etiqueta que no sean reconocidos por ella se incluirn sin modificar en el HTML generado, de forma que podemos hacer: Eg1action"ubmit value7AEliminarA action7AdeleteA onclicH7Areturn confirm(GEstTs seguroWWG)A @> y la etiqueta action"ubmit incluir el atributo onclicH en el html generado tal cual lo hemos definido nosotros.

EtiquetasparaAJAX
El uso de AJAX ("AsinchronousJavascript AndXML ") ha supuesto toda una revolucin en la forma de crear interfaces de usuario web, al permitir que un documento HTML pueda recargarse parcialmente haciendo llamadas asncronas al servidor. Grails incorpora una serie de etiquetas auxiliares que facilitan la generacin del cdigo
Pgina 110

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Javascript necesario para hacer este tipo de llamadas. Lo primero que debemos elegir es la librera Javascript que deseamos utilizar. Las etiquetas incluidas por defecto usan Prototype (http://www.prototypejs.org), aunque existen numerosos plugins que proporcionan soporte para otras libreras como Dojo (http://dojokit.org) o Yahoo UI (http://developer.yahoo.com/yui). Una vez elegida la librera, aadimos la etiqueta correspondiente a la cabecera de nuestra pgina GSP: Eg1,avascript librar(7Aprotot(peA @> Una vez incluida la librera Javascript, disponemos de distintas etiquetas para las situaciones ms habituales: remote#inH Genera un enlace que realiza una invocacin AJAX al servidor y muestra el contenido en el contenedor con el id proporcionado en el atributo "update": Ediv id7AlistadoA>E@div> Eg1remote#inH action7AlistA controller7ApersonaA update7AlistadoA> 'er #istado Completo E@g1remote#inH> form.emote Crea una etiqueta form de HTML con la lgica necesaria para hacer un submit AJAX de los datos, en lugar de un POST normal: Eg1form.emote name7AfA url7A8action1actuali/ar9A update7AresultadoA> . . . E@g1form.emote> Ediv id7AresultadoA>E@div> submit2o.emote crea un botn que enva el formulario actual mediante AJAX. Especialmente til en casos en que no podemos utilizar formRemote. Eg1form action7Aactuali/arA> b Eg1submit2o.emote update7AresultadoA @> E@g1form> Ediv id7AresultadoA>E@div> remote4ield Crea un campo de texto que enva su valor al servidor cada vez que se cambia. remote4unction Genera una funcin javascript que podemos asociar al evento que queramos de cualquier objeto HTML: Einput t(pe7AbuttonA name7AbA value7A'er 0suarioA onclicH7A$6remote4unction(action1Gsho&G);A @>

Pgina 111

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

EventosJavascript
La mayora de las etiquetas AJAX permiten asociar cdigo Javascript a ciertos eventos, ya sea para reaccionar ante la respuesta del servidor o bien para proporcionar al usuario informacin sobre lo que est ocurriendo. Los eventos que podemos capturar son: on"uccess la llamada se realiz con xito. on4ailure la llamada al servidor fall. onR8C*:P+*-E..*.-F22C9 la llamada al servidor devolvi un error on0ninitiali/ed la librera AJAX fall al inicializarse. on#oading la llamada se ha realizado y se est recibiendo la respuesta. on#oaded la respuesta se ha recibido completamente. onComplete la respuesta se ha recibido y se ha completado su procesamiento.

Veamos algunos ejemplos: Eg1,avascript> function traba,ando()6 alert(Avamos a conectar con el servidor...A)] ; function completado()6 alert(ACroceso completadoA)] ; function noEncontrado()6 alert(A#a ruta estaba mal...A)] ; function error()6 alert(AFa ocurrido un error en el servidorA)] ; E@g1,avascript> Eg1remote#inH action7Asho&A id7A<A update7AresultadoA on#oading7Atraba,ando()A onComplete7Acompletado()A onM>M7AnoEncontrado()A on=>>7Aerror()A> )ostrar la persona con id < E@g1remote#inH>

Pgina 112

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Ediv id7AresultadoA>E@div>

Detrs de cada peticin AJAX hay un objeto XmlHttpRequest que almacena los datos devueltos por el servidor as como el cdigo HTTP y otra informacin sobre el proceso. Tienes ms informacin sobre este objeto en la Wikipedia: http://es.wikipedia.org/wiki/XMLHttpRequest

Si necesitamos acceder al objeto [mlFttp.e%uest podemos utilizar el parmetro implcito e en las funciones Javascript: Eg1,avascript> function evento(e)6 alert(e)] ; E@g1,avascript> Eg1remote#inH action7AtestA on"uccess7Aevento(e)A> Crobar E@g1remote#inH>

GenerarXMLo JSONen el servidor


En los casos ms habituales, las invocaciones AJAX generan en el servidor un fragmento de HTML que insertamos en el div correspondiente. Pero no siempre resulta tan sencillo hacer algo as, y es posible que necesitemos devolver desde el servidor alguna estructura de datos para ser procesada va Javascript en el cliente. Como vimos en el captulo 8, generar XML o JSON en un Controlador es trivial gracias a los converters de Grails: import grails.converters.N class CersonaController 6 def sho& 7 6 def p 7 Cersona.get(params.id) render p as -"*B ; ; Al invocar esta accin desde AJAX tendramos que escribir el Javascript para procesar el cdigo JSON: Eg1,avascript>
Pgina 113

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

function actuali/ar(e)6 @@evaluamos el -"*B1 var p 7 eval(A(A + e.response2e3t + A)A)] $(personaActiva).innerF2)# 7 p.nombre ; E@g1,avascript> Ediv id7ApersonaActivaA>E@div> Eg1remote#inH action7Asho&A id7A=A on"uccess7Aactuali/ar(e)A> )ostrar persona con P: = E@g1remote#inH>

Usarlas etiquetascomomtodos
Todas las etiquetas GSP pueden invocarse como funciones, lo cual supone una gran ventaja para usarlas desde: atributos en otras etiquetas: Eimg src7A$6resource(dir1GimagesGIfile1Glogo.pngG);A @> Artefactos no GSP, como Controladores: def contenido 7 g.include(action1GstatusG)

CrearTagLibs
Con Grails es muy sencillo crear nuestra propia librera de etiquetas para encapsular la lgica de presentacin. Si alguna vez has creado una librera de etiquetas JSP, te sorprender lo rpido e intuitivo que resulta obtener el mismo resultado con GSP. Segn la convencin, en Grails una librera de etiquetas es una clase Groovy cuyo nombre termina en 2ag#ib y est alojada en la carpeta grails-app@taglib. Como siempre, podemos elegir entre crear el archivo manualmente o mediante el script correspondiente: grails create-tag-lib i&2ags Como ejemplo, vamos a crear una librera con una etiqueta que envuelve todo lo que pongamos dentro en un borde de color: class P&2ags2ag#ib 6
Pgina 114

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

static namespace 7 Ai&A def con5orde 7 6 atrIbod( -> out EE AEdiv st(le7Gborder-color1$6atr.color;G>A out EE bod(() out EE AE@div>A ;

Una vez creada la clase podemos utilizarla en cualquier vista GSP: Ei&1con5orde color7Acf==A>Fola a todosE@g1con5orde>A Al procesarse la etiqueta, el HTML que llegar al cliente sera as: Ediv st(le7Gborder-color1cf==G> Fola a todos E@div> Si no definimos la variable namespace en nuestra librera de etiquetas, Grails las asignar al espacio de nombres por defecto "g".

Utilizarlibrerasde etiquetasJSP
Adems de las libreras de etiquetas GSP, Grails soporta desde la versin 1.0 el uso de libreras de etiquetas JSP, mediante la directiva taglib: EQJ taglib prefi37AfmtA uri7Ahttp1@@,ava.sun.com@,sp@,stl@fmtA Q> Con la ventaja adicional de que podemos usarlas al estilo tradicional: Efmt1formatBumber value7A$6libro.precio;A pattern7A>.>>A @> y tambin como llamadas a mtodos: Einput t(pe7Ate3tA name7AprecioA value7A$6fmt.formatBumber(value1 >Ipattern1G.>G);A@>

Pgina 115

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Layouts:Sitemesh
SiteMesh (http://www.opensymphony.com/sitemesh) es un framework para construir interfaces web con un formato unificado. Se basa en el patrn Decorator,partiendo de un layout inicial de la pgina e incorporando modificaciones a partir de cada vista particular. El flujo de ejecucin al procesar una peticin sera similar a este:

P ticin (BBP "%P nd r


A Proc sa !a $gina A " n ra un docum nto (B&:

Contro!ador4
A Proc sa !a !gica r A < cid !a "%P a $roc sar

%it & s' ,ti!i6a ! docum nto 0 s$u sta (BBP g n rado $ara d corar

! !a=out = $roc sar ! docuA m nto d 1initi;o.

La principal ventaja de este sistema es que toda la estructura genrica (referencias a hojas de estilo, zonas fijas en la cabecera, men de navegacin, pie de pgina, etc) se definen en un nico archivo independiente de nuestras vistas GSP, con lo que se simplifica enormemente la gestin del look&feel de nuestra aplicacin:

Layout

Vista GSP Titulo Lorem ipsum dolor sit amet, Consectetur.

Titulo Lorem ipsum dolor sit amet, Consectetur.

El archivo en el que se define la estructura de la pgina debe ubicarse en la carpeta


Pgina 116

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

grails-app@vie&s@la(outs, y por lo dems puede contener el mismo tipo de elementos de una pgina gsp normal. Veamos un layout tpico: Ehtml> Ehead> Etitle> Eg1la(out2itle default7A"in 2$tuloA@> E@title> Eg1la(outFead @> E@head> Ebod( onload7A$6pageCropert((name1Gbod(.onloadG);A> Ediv id7AtopA>EZ--contenido fi,o-->E@div> Ediv id7AmainA> Eg1la(out5od( @> E@div> Ediv id7AbottomA> EZ-- contenido fi,o --> E@div> E@bod(> En este layout el trabajo interesante lo estn haciendo las etiquetas que incluyen elementos de la pgina GSP procesada: la(out2itle inserta el ttulo de la GSP procesada. la(outFead inserta el contenido de la cabecera de la GSP procesada. la(out5od( inserta el body de la GSP procesada. pageCropert( permite obtener elementos individuales de la GSP procesada, como por ejemplo atributos de una etiqueta concreta.

Cmoseleccionarel layoutpara una vista


La convencin en Grails dice que si no se indica lo contrario, el layout a aplicar para una accin ser el que se encuentre en grails-app@vie&s@la(outs@8controlador9@8accion9.gsp Si no se encuentra, se buscar grails-app@vie&s@la(outs@8controlador9.gsp Para modificar este comportamiento podemos especificar el layout a aplicar en el controlador: class CersonaController 6
Pgina 117

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@@"e buscarT en @@grails-app@vie&s@la(outs@custom@general.gsp static la(out 7 Gcustom@generalG ; o bien en la GSP: Ehtml> Ehead> Etitle> b E@title> Emeta name7Ala(outA content7AmainA>E@meta> b La ventaja del sistema de layouts es que podemos elegir la estructura de nuestra pgina en tiempo de ejecucin, creando por ejemplo una versin simplificada para navegadores sin soporte de Javascript, o para mostrar a usuarios que navegan desde un telfono mvil sin necesidad de modificar nuestras vistas GSP.

Pgina 118

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

11. < 1ini ndo !a structura d ,0:s d nu stra a$!icacin.

Pgina 119

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

La estructura de las URLs es ms importante en una aplicacin web de lo que inicialmente pudiera parecer. A fin de cuentas son la interfaz de comunicacin que mostramos al exterior, y representan los distintos comandos y vistas que nuestros usuarios pueden invocar. Una correcta poltica de URLs har que los usuarios sepan de forma intuitiva para qu sirve una direccin sin necesidad de visitarla con su navegador, y si estamos desarrollando un portal web, que los resultados que muestren los buscadores sean mucho ms auto-descriptivos. Imagina que te envan un enlace por e-mail para que accedas a un sitio web, y que el enlace en cuestin es como este: http1@@sitio.com@ui@portal.doWcmd7X\origin7mail ahora imagina que el enlace tiene esta pinta: http1@@sitio.com@emailmHt@primera'isita Puede que lo pulses o puede que no, pero est claro que en el segundo caso la direccin da mucha ms informacin que en el primero. Grails utiliza por defecto un convenio para las URLs como este: @controlador@accin@id pero no hay ninguna regla que nos impida adaptarlo a nuestros gustos o a las necesidades de nuestro proyecto. Para hacerlo tenemos que modificar el archivo grails-app@conf@0rl)appings.groov(. Por ejemplo: class 0rl)appings 6 static mappings 7 6 A@articulosA 6 controller7AarticuloA action7AlistA ; ; ; en este caso estaramos indicando que cuando el usuario invocase la URL /articulos, debera ejecutarse la accin list del controlador articulo. Al definir los patrones de url podemos utilizar variables: class 0rl)appings 6 static mappings 7 6 A@articulos@$(W@$mW@$dW@$idWA 6 controller7AarticuloA action7Asho&A
Pgina 120

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; ; ;

La GWG indica que la variable es opcional, de forma que se resolver el mapeo incluso si no se asigna valor para ella, aunque lgicamente no se guardar nada en params. Luego, en el controlador, accederamos a cada porcin de la url en el Map params, por el nombre que tena asignado: class ArticuloController 7 6 def sho& 7 6 def ado 7 params.( def mes 7 params.m def dia 7 params.d def id 7 params.id b ; ; En este caso, nuestro controlador tendra que asegurarse de que los datos pasados para el ao, el mes y el da son vlidos. Afortunadamente, Grails proporciona soporte para restringir los posibles valores mediante expresiones regulares: class 0rl)appings 6 static mappings 7 6 A@articulos@$(W@$mW@$dW@$idWA 6 controller7AarticuloA action7Asho&A constraints 6 ((matches1@d6M;@) m(matches1@d6K;@) d(matches1@d6K;@) ; ; ; ; Tambin podemos utilizar las variables reservadas controller, action e id para construir variantes del formato inicial de URLs: class 0rl)appings 6 static mappings 7 6 A@$controller@$id@$actionA() ;
Pgina 121

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; Adems de los fragmentos de la URL, podemos definir otras variables que tambin estarn accesibles en el controlador desde el Map params: class 0rl)appings 6 static mappings 7 6 A@articulos@$(@$mA 6 order 7 AfechaA sort 7 AascA controller 7 AarticuloA action 7 AlistA ; ; ;

CmoafectaUrlMappingsa la etiquetalink
Como vimos en el captulo sobre GSP, la etiqueta linH construye enlaces a nuestras acciones y controladores. Lo mejor de todo es que lo hace teniendo en cuenta nuestra poltica de enlaces, de manera que si cambiamos la configuracin en el archivo UrlMappings la etiqueta seguir generando enlaces correctamente: Eg1linH controller1GarticuloG action1GlistG params18(1GK>>?GIm1G KG9> 'er art$culos E@g1linH> El enlace generado ser (segn la configuracin del ltimo ejemplo): Ea href7A@articulos@K>>?@ KA>'er art$culosE@a>

Capturarcdigosde error
Podemos mapear cdigos de error HTTP a controladores y acciones: class 0rl)appings 6 static mappings 7 6 A=>>A(controller1GerroresGIaction1GserverErrorG) AM>MA(controller1GerroresGIaction1Gnot4oundG)
Pgina 122

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; ; O bien simplemente a vistas GSP: class 0rl)appings 6 static mappings 7 6 A=>>A(vie&1A@error@serverErrorA) AM>MA(vie&1A@error@not4oundA) ; ;

CapturarmtodosHTTP
Otra opcin muy interesante es usar acciones distintas de un controlador en funcin del mtodo HTTP utilizado, al estilo REST : class 0rl)appings 6 static mappings 7 6 A@persona@$idA 6 action 7 8 +E21Gsho&GI C021GupdateGI :E#E2E1GdeleteGI C*"21GsaveG 9 ; ; ; De esta manera, Grails invocar una accin distinta de nuestro controlador en funcin del mtodo HTTP utilizado para la peticin. Si simplemente ponemos la url @persona@M en nuestro navegador, estaremos haciendo una peticin GET, mientras que si enviamos un formulario que tiene esa URL como destino, estaremos haciendo una peticin POST. Los mtodos PUT y DELETE no estn soportados en la mayora de los navegadores, pero son muy tiles para hacer nuestro propio cliente REST (ver captulo 18).

Patronesde URLsconnombre
Desde la versin 1.2, Grails soporta la posibilidad de asociar un nombre a cada regla de gestin de URLs, y una manera ms explcita de crear enlaces que sigan una regla particular. Por ejemplo:

Pgina 123

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

name posts5(2ag1 A@blog@$seccion@$tagWA 6 controller 7 AblogCostA action 7 Asho&A ;

Una vez definido el patrn de URLs, podemos crear enlaces de esta manera: ElinH1posts5(2ag seccion7Asoft&areA tag7Agroov(A> Costs sobre +roov( E@linH1posts5(2ag> Fjate que estamos usando la etiqueta link:postsByTag, que en realidad no existe. Se trata de un mecanismo para decirle a Grails que genere una url siguiendo ese formato particular.

Pgina 124

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

12. C ) 8!o2s

Pgina 125

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Los Web Flows (Flujos Web) son la versin HTTP de los tpicos asistentes en programas de escritorio. Se trata de una conversacin entre el navegador y la aplicacin web que se extiende a lo largo de varias peticiones manteniendo un estado entre ellas. Podemos definir el estado inicial y el final, y gestionar la transicin entre estados. IMPORTANTE : A partir de la versin1.2, el soporteparaWebFlowsha sidoextradoa un plugin , as que si necesitamos hacer uso de esta funcionalidad deberemos instalarlo explcitamente mediante grails install-plugin &ebflo&. La convencin en Grails es que cualquier accin cuyo nombre termine en 4lo& definir un flujo web. Lo vers mejor con un ejemplo. Supongamos que estamos desarrollando una red social profesional, en la que cada usuario tiene un perfil con varios apartados (datos personales, formacin, experiencia laboral y objetivos). Podemos usar un web flow para definir el perfil: class CrofileController 6 def inde3 7 6 redirect(action1GdefineG) @@4$,ate1 no usamos el G4lo&G al final. ; def define4lo& 7 6 personal 6 on(GsubmitG)6CersonalCmd cmd -> flo&.personal 7 cmd if(flo&.personal.validate()) return success() else return error() ;.to GformacionG on(GcancelG).to GcancelG ; formacion 6 on(GsubmitG)64ormacionCmd cmd -> flo&.formacion 7 cmd if(flo&.formacion.validate()) return success() else return error() ;.to Ge3perienciaG on(GbacHG).to GformacionG on(GcancelG).to GcancelG ; e3periencia 6 on(GsubmitG)6E3perienciaCmd cmd -> flo&.e3periencia 7 cmd if(flo&.e3periencia.validate())
Pgina 126

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

return success() return error() ;.to Gob,etivosG on(GbacHG).to Ge3perienciaG on(GcancelG).to GcancelG else

; ;

; ob,etivos 6 on(GsubmitG)6*b,etivosCmd cmd -> flo&.ob,etivos 7 cmd if(flo&.ob,etivos.validate()) return success() else return error() ;.to GsaveCrofileG on(GbacHG).to Ge3perienciaG on(GcancelG).to GcancelG ; saveCrofile 6 @N +enerar el perfil con los ob,etos cmd. N@ ; cancel 6 redirect(controller1GhomeG) ;

Analicemos detenidamente el ejemplo anterior, paso por paso: La accin por defecto, inde3, redirige al navegador hacia el flujo. Fjate que el nombre oficial de la accin no incluye el sufijo 4lo&. La accin que define el flujo se llama define4lo&, y en su interior se establecen todos los pasos posibles y la forma de pasar de uno a otro. Las vistas asociadas a cada paso se buscarn en grailsapp@vie&s@profile@define@. Lo primero que veremos ser el estado inicial, definido en la vista grails-app@vie&s@profile@define@personal.gsp. Esta pgina deber contener el primer formulario, con los botones necesarios para lanzar los eventos submit y cancel: Eg1form action7GdefineG> . . . Eg1submit5utton name7GsubmitG value7G"iguienteG>E@g1submit5utton> Eg1submit5utton name7GcancelG value7GCancelarG>E@g1submit5utton>
Pgina 127

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

E@g1form> En cada paso del flujo podemos utilizar Command Objects (ver captulo 8) para la validacin de los datos de entrada. Adems de los mbitos que ya conocemos (session, request, flash, etc), disponemos del mbito flow, en el que podemos guardar los datos relacionados con este proceso y sern destruidos cuando termine la ejecucin del ltimo paso. Cuando realizamos la validacin de los datos de entrada, utilizamos los mtodos estndar success() y error(), que permiten seguir adelante o volver a mostrar el formulario para que el usuario corrija los errores, respectivamente. Como ves, los Web Flows son una forma muy potente de crear funcionalidades tipo asistente en nuestras pginas. Con este sistema puedes implementar fcilmente asistentes de instalacin, carros de la compra, o cualquier otro caso de uso en el que necesites una entrada de datos compleja que deba ser validada por lotes.

Pgina 128

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

13. 8i!tros

Pgina 129

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Como ya vimos en el captulo 8, los controladores soportan la posibilidad de definir Interceptors, que se ejecutan antes y/o despus de nuestras acciones. Sin embargo, existen casos en los que necesitamos interceptar varias (o todas) de las URLs de nuestra aplicacin, y no queremos introducir ese cdigo en nuestros controladores. El caso de uso tpico es cualquier caracterstica transversal de nuestra aplicacin, como control de acceso, trazas, o el filtro XSS (cross-site scripting ). Este tipo de funcionalidad merece ser implementada en componentes aparte, independientes del resto de la lgica de negocio y sencillos de mantener. La convencin sobre Filtros es que cualquier clase que se encuentre en la carpeta grails-app@conf cuyo nombre termine en 4ilters, y que contenga un bloque de cdigo filters podr interceptar las URLs de la aplicacin. Como siempre, podemos crear tal archivo a mano o mediante el comando grails create-filters 8nombre9. Por ejemplo: class )is4iltros4ilters 6 def filters 7 6 access4ilter(controller1GNGIaction1GNG)6 before 7 6 if(Zsession.usr \\ ZactionBame.e%uals(GloginG))6 redirect(action1GloginG) return false] ; ; ; ; ; Este filtro se aplicar sobre todas las peticiones (todos los controladores y todas las acciones). Si el valor de session.usr es null se enviar al usuario al formulario de login (salvo que est solicitando precisamente ese formulario). Los filtros pueden hacer dos cosas nicamente: Redirigir al usuario a otra URL mediante el mtodo redirect. Generar una respuesta mediante el mtodo render. Tambin se pude restringir la aplicacin del filtro por URI: filtro(uri1G@persona@NNG)6 . . . ; Como habrs notado, en el ejemplo hemos introducido el cdigo en un bloque before. En Grails los filtros pueden definir cdigo que se ejecute en distintos momentos del procesado de la peticin: before El cdigo se ejecutar antes de invocar a la accin. Si devuelve false, la
Pgina 130

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

accin no se llegar a ejecutar nunca. after Se ejecuta tras la accin. Podemos recibir el modelo generado mediante un parmetro en la closure. after'ie& Se ejecuta despus de renderizar la vista.

En un filtro podemos acceder a todos los entornos disponibles en controladores y libreras de tags: re%uest response session servletConte3t flash params actionBame controllerBame grailsApplication applicationConte3t

Ejemplo:filtro XSS
Como ejemplo del tipo de cosas que podramos El ataque de tipo XSS consiste en pasar querer hacer con un Filtro, supongamos que cdigo HTML y/o javascript como parmetro tenemos una aplicacin web en la que necesitamos en una llamada a la aplicacin web. Si en el controlador se muestra el valor del parmetro introducir una proteccin contra Cross Site directamente, sin filtrar, es posible inyectar Scripting. Para ello vamos a utilizar una clase de cdigo en nuestra pgina que aada como por ejemplo redirigir al utilidad en Groovy que realice el trabajo de eliminar funcionalidad, usuario a un sitio falso. el marcado de una cadena de texto: class )arHup0tils 6 static "tring remove)arHup("tring original) 6 def rege3 7 AE@WYY&+((YYs+YY&+ (YYsN7YYsN(W1YA.NWYAeG.NWGe8fYGYA>YYs9+))W) +YYsNeYYsN)@W>A def matcher 7 original 7a rege3] def result 7 matcher.replaceAll(AA)] return result] ; ;
Pgina 131

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El mtodo remove)arHup recibe una cadena de texto y elimina cualquier fragmento que tenga forma de etiqueta xml. Para poder usar esta clase debemos guardarla en la carpeta src@groov(@ de nuestro proyecto. Ahora tenemos que construir un filtro que aplique esta funcionalidad sobre los parmetros de cada peticin: class PL4ilters6 def filters 7 6 3ss(controller1GNGI action1GNG) 6 before 7 6 def debug 7 false if(debug) println re%uest.method if(true ee re%uest.method 77 G+E2G)6 params.each 6 entr( -> if(entr(.value instanceof "tring)6 params8entr(.He(9 7 )arHup0tils.remove)arHup(entr(.value) ; ; ; ; ; ; ; Para cada peticin, antes de invocar a la accin correspondiente, este filtro eliminar de los parmetros cualquier cdigo de marcado. De esta manera estamos seguros de que llegarn limpios a nuestro constructor y no tendremos que mezclar tareas de seguridad con nuestra lgica de negocio. Esta es una de las muchas ventajas de que el Map para"s sea mutable: podemos alterar los parmetros de entrada, ya sea por motivos de seguridad como en este caso, o simplemente para aadir valores por defecto.

Pgina 132

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

14. Dat r#as d

$ru )as

Pgina 133

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Si las pruebas son importantes en cualquier metodologa de desarrollo de software, lo son an ms en las metodologas giles. La razn est en que, aparte de comprobar si los algoritmos estn o no bien implementados, un buen conjunto de pruebas permite obtener informacin rpidamentesobre el estado de nuestro desarrollo. Y precisamente uno de los objetivos que se persiguen en los procesos giles es acortar el intervalo de tiempo que pasa entre que realizamos alguna actividad (un cambio en los requisitos, una nueva implementacin de un caso de uso, etc) y obtenemos informacin sobre el efecto que la actividad ha tenido en el proyecto. Las bateras de pruebas en un proyecto de software deben satisfacer por tanto dos objetivos bien diferenciados: Asegurarla calidad. Mediante pruebas unitarias y de integracin definimos cmo debe comportarse el sistema, de manera que ese comportamiento se mantenga con el tiempo. Adems, cuando se descubre un fallo en el software se construye un caso de prueba que lo reproduce, y nos asegura que una vez resuelto no volver a aparecer. Monitorizarel procesode desarrollo. Si durante la fase de anlisis desarrollamos una batera de pruebas que nos permita comprobar qu funcionalidades estn implementadas en un momento dado del tiempo, ser mucho ms fcil saber en qu punto del desarrollo nos encontramos y podremos detectar desviaciones de plazo con mayor antelacin. Por tanto, cualquier entorno que pretenda dar soporte al desarrollo gil de aplicaciones debe prestar especial atencin a las pruebas. Grails no es una excepcin en este punto, e verifican las llamadas que se realizan sobre stos, comprobando el orden y la cantidad de incluye un potente sistema de testing ellas. aprovechando el soporte nativo en Groovy para Stubs: objetos que sustituyen a recursos pero distintas formas de Mocks y Stubs. Cada vez que no realizan una comprobacin estricta del generamos un artefacto mediante una llamada a orden y cantidad de las llamadas. grails create-___, el comando en cuestin Ms informacin sobre Groovy mocks en generar, adems del componente solicitado, un http://groovy.codehaus.org/Groovy+Mocks caso de pruebas para verificar su funcionamiento. Lgicamente, seremos nosotros los responsables de implementar las pruebas del componente. Durante el proceso de desarrollo, podemos probar el estado de nuestra aplicacin mediante el comando: grails test-app Este script ejecutar todas las pruebas unitarias y de integracin de nuestro proyecto, y generar un informe al que podremos recurrir en caso de fallos:
Mocks: objetos que sustituyen a recursos y

Pgina 134

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 135

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El informe se genera en texto y html, lo cual resulta especialmente interesante si queremos que las bateras de tests se ejecuten de forma desatendida durante la noche como parte de nuestro proceso de integracin continua. Podemos programar un script que enve el resultado de las pruebas cada maana por email al jefe de proyecto, o publicar la versin html en el servidor web de integracin:

Pgina 136

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Para adentrarnos en el proceso de generacin de bateras de pruebas, vamos a trabajar sobre una aplicacin en la que tenemos una entidad Persona con este aspecto: class Cersona 6 static has)an( 7 8amigos1Cersona9 "tring nombre "tring apellidos "tring email :ate fechaBacimiento static constraints 7 6 nombre(si/e1<..=>IblanH1false) apellidos(si/e1<.. >>IblanH1true) fechaBacimiento() email(email1true) ;

como ves, hemos definido una relacin uno a muchos de la clase Persona consigo misma, de forma que una persona puede tener varios amigos, y a la vez figurar como amigo de varias otras. Lo que haremos ahora es crear un servicio con un mtodo que garantice que cuando existe una relacin de amistad, sta sea mutua: class +ente"ervice 6 boolean transactional 7 false
Pgina 137

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@NN "e asegura de %ue ambas personas se tengan como amigos. N@ def add2o4riends(Cersona p I Cersona pK)6 if(Zp .amigos.contains(pK))6 p .amigos.add(pK) ; if(ZpK.amigos.contains(p ))6 pK.amigos.add(p ) ; ; ;

Testsunitarios
Los test unitarios son aquellos en los que se verifica que un mtodo se comporta como debera, sin tener en cuenta su entorno. Esto significa que cuando se ejecutan las pruebas unitarias de un mtodo Grails no inyectar ninguno de los mtodos dinmicos con los que contamos cuando la aplicacin se est ejecutando. As que, cuando trabajemos con entidades o servicios seremos nosotros los responsables de crear y gestionar todos los objetos. Para crear un test unitario de nuestro servicio ejecutaremos el script: grails create-unit-test gente0nitario el cual crear una nueva batera de pruebas en la carpeta test@unit de nuestro proyecto: import grails.test.N class +ente0nitario2ests e3tends +rails0nit2estCase 6 protected void set0p() 6 super.set0p() ; protected void tear:o&n() 6 super.tear:o&n() ; void test"omething() 6 ;
Pgina 138

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; Como ves, la clase generada hereda de +rails0nit2estCase, lo que hace que tengamos a nuestra disposicin una serie de mtodos para facilitarnos la tarea de probar nuestro servicio. Lo que haremos ahora es sustituir el mtodo de ejemplo testSomething por algo ms util para nosotros: void testAdd2o4riends() 6 Cersona p 7 ne& Cersona( nombre1GBachoGI apellidos1GbritoGI email1GnachoJimagina&orHs.comGI amigos189) Cersona pK 7 ne& Cersona( nombre1G-acintoGI apellidos1G5enaventeGI email1G,cbvJtest.comGI amigos189) def testPnstances 7 8p IpK9 mocH:omain(CersonaItestPnstances) def srv 7 ne& +ente"ervice() srv.add2o4riends(p IpK) assert2rue p .amigos.contains(pK) assert2rue pK.amigos.contains(p )

Como hemos visto al principio del captulo, este test se ejecutar sin levantar el contexto Grails, de forma que las entidades no disponen de los mtodos dinmicos inyectados por GORM, ni se realiza la inyeccin de dependencias. Entonces, por qu podemos probar el servicio? La mayor parte de la magia la realiza el mtodo mocH:omain.

Los mtodosmock
La clase GrailsUnitTestCase pone a nuestra disposicin mtodos para que nuestros objetos se comporten en pruebas como lo haran en ejecucin: mocH:omain(claseItestPnstances7) - Toma la clase proporcionada como primer parmetro y la altera para aadir toda la funcionalidad de una entidad en GORM. Aade tanto los mtodos estticos (get(), count(), etc) como los de instancia (save(), delete(), etc). El segundo parmetro es una lista en la que se irn almacenando las instancias de la clase cada vez que se invoque el mtodo save(). mocH4orConstraints2ests(claseI testPnstances7) - Permite comprobar
Pgina 139

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

el funcionamiento de las reglas de validacin en clases de entidad y objetos comando. Por ejemplo: void test'alidaciones() 6 mocH4orConstraints2ests(CersonaI89) Cersona p 7 ne& Cersona() @@ . probar %ue no puede haber nulos assert4alse p.validate() assertE%uals GnullableGIp.errors8GnombreG9 assertE%uals GnullableGIp.errors8GapellidosG9 assertE%uals GnullableGIp.errors8GemailG9 @@K. probar la validacin del email p.email 7 GEmail incorrectoG assert4alse p.validate() assertE%uals GemailGIp.errors8GemailG9 ; mocH#ogging(clase, enableDebug = false) aade la propiedad log a la clase proporcionada. Todos los mensajes de log sern trazados por consola. mocHController(clase) aade todas las propiedades y mtodos dinmicos a la clase indicada para que se comporte como un controlador. mocH2ag#ib(clase) aade todas las propiedades y mtodos dinmicos a la clase proporcionada para que se comporte como una librera de etiquetas GSP.

Gracias a estos mtodos, podemos probar nuestros artefactos y usar los mtodos dinmicos de Grails sin necesidad de levantar el contexto de ejecucin.

Testsde integracin
Las pruebas de integracin tienen por objetivo verificar el comportamiento de cada componente teniendo en cuenta el contexto. Esto significa que, a diferencia de los tests unitarios, al ejecutar estas pruebas todos los componentes tendrn acceso al entorno de ejecucin completo de Grails: mtodos y propiedades dinmicos, inyeccin de dependencias y base de datos. Para demostrar el uso de este tipo de pruebas vamos a aadir a nuestra aplicacin un controlador para gestionar entidades Persona. De momento slo crearemos una accin, que nos mostrar un listado de personas en XML: import grails.converters.[)# class +enteController 6 @@ 0.#1 @gente@to[)# def to[)# 7 6
Pgina 140

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@N :efinimos valores de ordenacin ( paginacin por defecto. N@ if(Zparams.ma3) params.ma3 7 K= if(Zparams.offset) params.offset 7 > if(Zparams.order) params.sort 7 GidG if(Zparams.sort) params.order 7 GdescG @@+eneramos el listado en [)# render Cersona.list() as [)# ; ;

El resultado de invocar la url @gente@to[)# sobre nuestra aplicacin ser algo as:

Pgina 141

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Al crear el controlador, Grails ha generado una batera de pruebas en el archivo test@unit@+enteController2ests.groov( que podemos utilizar con las herramientas del apartado anterior, pero ahora nos interesa hacer pruebas de integracin as que tenemos que crear la batera correspondiente: grails create-integration-test gente El archivo generado se guardar en test@integration@+ente2ests.groov(. Lo que haremos es crear un caso de prueba para comprobar que la accin genera el listado correcto de personas: import grails.test.N class +ente2ests e3tends +rails0nit2estCase 6 protected void set0p() 6 super.set0p() ; protected void tear:o&n() 6 super.tear:o&n()
Pgina 142

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; void test2o[)#() 6 Cersona p 7 ne& Cersona( nombre1GBachoGI apellidos1G5ritoGI email1GnachoJimagina&orHs.comG ).save()] def gc 7 ne& +enteController() gc.to[)#() def resp 7 gc.response def 3ml"tr 7 resp.contentAs"tring def listado 7 ne& [ml"lurper() .parse2e3t(3ml"tr) assertE%uals resp.content2(peI Gte3t@3mlG assertE%uals I listado.persona.si/e() assertE%uals p.id I listado.persona8>9.Jid.te3t().to#ong() ; ; Cosas en las que debes fijarte: Lo primero que hacemos es crear una entidad de tipo Persona. Por defecto Grails borrar todos los datos despus de ejecutar cada prueba. Despus instanciamos el controlador e invocamos la accin. Como esta accin no devuelve un modelo, para procesar el resultado utilizamos el objeto response (en realidad es un )ocHFttp"ervlet.esponse de Spring) Procesamos la respuesta con un objeto XmlSlurper de Groovy, que nos permite tratar el xml como si fuera un rbol de objetos (ver APNDICE A). Vamos ahora a aadir otra accin a nuestro controlador que guarde una entidad. Deber recibir los datos en el mapa params y crear o actualizar una entidad segn el caso, y como hemos comentado que la lgica de negocio no debera estar en los controladores, vamos a delegar el trabajo en nuestro servicio GenteService. Lo primero ser por tanto implementar el mtodo de servicio: class +ente"ervice 6 @@ . . . public Cersona save*r0pdate(params)6 def p if(params.id)6
Pgina 143

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

p 7 Cersona.get(params.id) ; else6 p 7 ne& Cersona() ; p.properties 7 params p.save() ; @@ . . . ; y la accin en el controlador: import grails.converters.[)# class +enteController 6 def gente"ervice @@ . . . def save 7 6 def p 7 gente"ervice.save*r0pdate(params) if(p.hasErrors())6 flash.message 7 G"e produ,eron erroresG ; return p ;

; Este caso tiene dos diferencias importantes con el anterior: por un lado, el controlador necesita una instancia del servicio, y por otra, el resultado no se escribe directamente en la respuesta, sino que la accin devuelve un modelo para ser representado en la vista correspondiente. Veamos el caso de prueba: import grails.test.N class +ente2ests e3tends +rails0nit2estCase 6 def gente"ervice @@ . . . void test"ave() 6 def gc 7 ne& +enteController() gc.gente"ervice 7 gente"ervice gc.params.nombre 7 G4ranciscoG gc.params.apellidos 7 GE,emploG gc.params.email 7 G,gJtest.comG def p 7 gc.save()
Pgina 144

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; ;

assertBotBull p assertE%uals G4ranciscoGIp.nombre assertBotBull p.id

@@ . . .

En este caso, debemos proporcionar a mano la instancia al servicio a nuestro controlador, as que es el caso de prueba el que declara la dependencia, y asigna el valor a la propiedad correspondiente de GenteController. Adems, fjate en que rellenamos el mapa params a mano, y que tratamos el objeto devuelto directamente. En particular, comprobamos que el id de la persona creada no es nulo, como prueba de que se ha almacenado en la base de datos.

Testsfuncionales
Los tests funcionales son los que se realizan sobre la aplicacin en ejecucin, y comprueban la implementacin de los casos de uso desde la perspectiva del usuario. Grails no incorpora ninguna funcionalidad estndar para automatizar este tipo de pruebas, aunque podemos incorporarla mediante el plugin webtest , que proporciona soporte para Canoo WebTest: grails install-plugin &ebtest Una vez instalado, podemos generar nuestros tests mediante el comando: grails create-&ebtest persona El nombre que demos debe ser el de la entidad para la que queremos generar el test. El plugin construir un test funcional completo sobre las vistas y acciones CRUD que luego podremos modificar: class Cersona2est e3tends grails.util.Leb2est 6 @@ 0nliHe unit testsI functional tests @@are sometimes se%uence dependent. @@ )ethods starting &ith GtestG &ill be @@ run automaticall( in alphabetical order. @@ Pf (ou re%uire a specific se%uenceI prefi3 @@ the method name (follo&ing GtestG) @@ &ith a se%uence @@ e.g. test>> Cersona#istBe&:elete def testCersona#istBe&:elete() 6 invoHe GpersonaG
Pgina 145

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

verif(2e3t

GFomeG

verif(#ist"i/e > clicH#inH GBe& CersonaG verif(2e3t GCreate CersonaG clicH5utton GCreateG verif(2e3t G"ho& CersonaGI description1G:etail pageG clicH#inH G#istGI description1G5acH to list vie&G verif(#ist"i/e group(description1Gedit the one elementG) 6 sho&4irstElement:etails() clicH5utton GEditG verif(2e3t GEdit CersonaG clicH5utton G0pdateG verif(2e3t G"ho& CersonaG clicH#inH G#istGI description1G5acH to list vie&G ; verif(#ist"i/e group(description1Gdelete the onl( elementG) 6 sho&4irstElement:etails() clicH5utton G:eleteG verif([Cath 3path1 A@@div8Jclass7GmessageG9AI te3t1 @.NCersona.Ndeleted.N@I rege31 true ; verif(#ist"i/e > ; "tring .*LRC*0B2R[CA2F 7 Acount(@@div8Jclass7GlistG9@@tbod(@tr)A def verif(#ist"i/e(int si/e) 6 ant.group( description1Averif( Cersona list vie& &ith $si/e ro&(s)A) 6 verif(2e3t GCersona #istG verif([Cath 3path1 .*LRC*0B2R[CA2FI te3t1 si/eI description1A$si/e ro&(s) of data e3pectedA ;
Pgina 146

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; def sho&4irstElement:etails() 6 clicH#inH G GI description1Ggo to detail vie&G ;

Como ves, el plugin incorpora toda una estructura para verificar la el html generado en cada vista, navegar por los elementos y pulsar sobre botones y enlaces. Para ejecutar los tests utilizamos el comando: grails run-&ebtest Entonces el plugin arrancar la aplicacin en modo tests, y navegar por las urls configuradas aplicando las reglas definidas en los tests. Cuando termine generar un informe en html con los resultados:

Pgina 147

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 148

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Para ms informacin sobre este tema, puedes consultar la documentacin del plugin en la pgina oficial de Grails: http://grails.org/Functional+Testing .

Pgina 149

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

15. Int rnaciona!i6acin

Pgina 150

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Internacionalizar una aplicacin significa disearla de forma que la interfaz de usuario soporte distintos idiomas sin que sea necesario modificar el cdigo fuente.

CmomanejaGrailsla i18n
Con Grails tenemos soporte para internacionalizacin (o i18n, como dicen en EEUU, poniendo la i, la n, y el nmero de letras que hay en medio, 18) por medio de archivos de recursos (resourcebundles ) almacenados en la carpeta grails-app@i !n. Los archivos de recursos son ficheros properties de Java en los que se guardan las distintas versiones de cada mensaje en todos los idiomas soportados por nuestra aplicacin. Cada idioma est definido en un fichero distinto que incluye en su nombre el Locale del idioma, por ejemplo: messages_es_AR.properties para los mensajes en espaol de Argentina messages_es_ES.properties para los mensajes en espaol de Espaa messages_en.properties para los mensajes en ingls etc. Desde el momento en que creamos nuestro proyecto Grails coloca en la carpeta correspondiente archivos de mensajes para 11 idiomas distintos:

Si necesitamos incluir ms idiomas en nuestra aplicacin slo tenemos que crear los archivos de recursos correspondientes y guardarlos en la carpeta junto a los dems. Fjate en que hay un archivo que no lleva el nombre de ningn locale en el ttulo: messages.propertes. Si Grails no sabe qu idioma debe emplear (ahora veremos cmo funciona el proceso de eleccin de idioma), coger los mensajes de ese archivo.
Pgina 151

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Para decidir qu idioma mostrar a un usuario, Grails lee el valor de la cabecera Accept-Language que todos los navegadores envan en cada peticin. Si queremos cambiar el idioma y hacer que Grails ignore la cabecera, podemos aadir el parmetro lang en cualquier URL para forzar a Grails a usar un idioma particular:

/persona/create?lang=es Desde ese momento nuestra eleccin quedar registrada en un Cookie y se usar en las siguientes peticiones.

Cmomostrarmensajesen el idiomacorrecto
Si queremos que nuestra aplicacin muestre los mensajes a cada usuario en el idioma que haya seleccionado, tenemos que escribir nuestras vistas y controladores teniendo en cuenta los archivos de recursos. En lugar de definir los mensajes de texto directamente en las GSP, tendremos que utilizar la etiqueta message:

<g:message code=mi.mensaje.localizado /> De esta manera, Grails buscar en el archivo messages del idioma correspondiente una fila como esta: mi.mensaje.localizado = Hello my friend! Si lo necesitamos podemos incluir parmetros en los mensajes:

mi.mensaje.localizado = Hello {0}! you have {1} messages. y proporcionar valores mediante el parmetro args en la etiqueta message: <g:message code=mi.mensaje.localizado args=${[user.name,user.messages.size()]} El patrn {0} se sustituir por el primer valor de la lista, el {1} por el segundo, y as sucesivamente.

Pgina 152

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Generarscaffoldinginternacionalizado
Desde la versin 1.2 de Grails, el scaffolding se genera de forma que las etiquetas de los campos y los mensajes de error se leen desde nuestros archivos de recursos. De esta manera, podemos incluir en messages.properties valores como: persona.label = Persona persona.nombre.label = Nombre Hasta la versin 1.2, las plantillas que usa Grails para generar el scaffolding no estaban preparadas para usar los archivos de recursos. Si estamos trabajando con una versin anterior a la 1.2 y necesitamos que el cdigo generado sea capaz de hablar distintos idiomas tendremos que instalar el plugin i !n-templates:

grails install-plugin i18n-templates Este plugin instala en tu aplicacin plantillas de scaffolding para que cada vez que generes los controladores y las vistas no se utilicen las plantillas estndar. Una vez instalado podemos generar el scaffolding para nuestras entidades, pero cuando vuelvas a arrancar la aplicacin comprobars que no ha cambiado nada, todo sigue saliendo en ingls. La buena noticia es que las vistas ahora tienen en cuenta tus archivos de recursos, as que lo nico que has de hacer es definir los mensajes en los idiomas que necesites y tu aplicacin los usar automticamente. Para saber qu mensajes debes generar puedes invocar el comando grails generate-i !n-messages gN^ que volcar por consola la lista de claves que has de aadir a tus archivos de propiedades. Si lo hacemos para la aplicacin de trucos de Groovy que comenzamos en el primer captulo obtenemos un resultado como este:

Pgina 153

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 154

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Todo lo que tienes que hacer ahora es copiar la salida por la consola en un archivo de recursos, por ejemplo, grails-app@i !n@scaffold.properties, y hacer todas las copias que necesites para los distintos idiomas (scaffoldRen.propertiesI scaffoldRit.propertiesI etc). Cuando vuelvas a ejecutar tu aplicacin vers que si invocas la url /usuario/list?lang=XY obtendrs el resultado en el idioma seleccionado:

Pgina 155

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Tienes ms informacin sobre el plugin en la pgina oficial: http://grails.org/I18n+Templates+Plugin

Pgina 156

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

16. % guridad

Pgina 157

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Grails cuenta con varios mecanismos de seguridad para evitar ataques de inyeccin de SQL y HTML: Todo el SQL generado en GORM se escapa para evitar inyeccin de SQL. Cuando generamos HTML mediante scaffolding, los datos se escapan antes de mostrarse. Las etiquetas que generan URLs (link, form, createLink, resource, etc) utilizan los mecanismos de escapado apropiados.
Escapar: en un lenguaje de programacin o marcado, sustituir caracteres que tienen funcionalidad por secuencias que representan el carcter pero no la funcionalidad. P.ej. En HTML, sustituir '>' por '&gt;'

Adems, la propia Mquina Virtual Java hace las labores de cajn de arena para evitar problemas de desbordamiento de memoria y ejecucin de cdigo malicioso.

Sin embargo, no hay nada que un framework pueda incluir que evite el principal origen de agujeros de seguridad: los errores de programacin. La mayora de los ataques que se reciben en aplicaciones web tienen que ver con tcnicas incorrectas o mal aplicadas en alguno de estos contextos: Generacinde consultasa la basede datos . Si construimos consultas SQL, o incluso HQL de Hibernate, introduciendo parmetros de la peticin HTTP sin procesar, estamos expuestos a ataques de inyeccin de SQL. Generacinde html. Si en nuestras GSP mostramos valores recibidos como parmetros en la peticin, y no los escapamos, estamos expuestos a ataques de inyeccin de HTML (y Javascript).

Tiposde ataques
Para prevenir ataques, es importante conocer los distintos tipos a los que podemos enfrentarnos. Veamos algunos de ellos.

Inyeccinde SQL
Imagina una accin en la que incluyes la siguiente consulta: def login 7 6 def % 7 gfrom 0suario as u &here u.login7G^+ params.username +^G and u.pass&ord7G^ + params.pass&ord + ^G^ def u 7 0suario.find(%) ; ...

Pgina 158

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Nuncadeberamos construir una consulta de este modo, porque qu pasa si en el campo password del formulario alguien introdujese esto:? CacoG or 7

Lo que pasara es que la consulta generada permitira acceso a cualquiera a nuestra aplicacin. La forma correcta de implementar esta accin es la siguiente: def login 7 6 def % 7 gfrom 0suario as u &here u.login7W and u.pass&ord7W^ def u 7 0ser.find(%I 8params.usernameIparams.pass&ord9) ... ; Al usar esta forma de construccin de consultas obligamos a Hibernate a procesar los parmetros y escapar todos los caracteres especiales, en el caso anterior la comilla simple, de forma que el ataque ya no tendra efecto.

Denegacinde servicio
Los ataques de denegacin de servicio (DoS, Denial of Service) consisten en aprovechar una gestin incorrecta de los recursos de una aplicacin para realizar peticiones masivas y provocar su saturacin. Imagina que tienes una web con una accin como esta: def list 7 6 if(Zparams.ma3) params.ma3 7 K= if(Zparams.offset) params.offset 7 > return Cersona.list(params) ; Qu ocurre si alguien invoca la accin con esta URL?: @8aplicacin9@8controlador9@listWma37?????????????? Lo que pasar es que terminars con un nmero de objetos Persona en memoria que seguramente ser inmanejable por el servidor de aplicaciones, y como mnimo notars
Pgina 159

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

un descenso en el rendimiento de tu aplicacin. La solucin a esto sera limitar el mximo de esta manera: def list 7 6 if(Zparams.ma3) params.ma3 7 K= if(Zparams.offset) params.offset 7 > params.ma* = Math.ma*+params.ma*,1--. return Cersona.list(params)

Inyeccinde HTML/Javascript
Ahora imagina que tienes una aplicacin web de noticias que admite comentarios de los usuarios, y que en la GSP en la que muestras los comentarios haces algo as: Eh >ComentariosE@h > Eg1each in7^$6comentarios;^> Ediv class7^comentario^>$6it.te3to;E@div> E@g1each> y si alguien publicase un comentario como este? >Escript>document.location7Ghttp1@@sitioRhacHers@cooHie .cgiWG +document.cooHieE@script> Lo que ocurrira es que al mostrar el parmetro de la consulta en tu html de salida estaras dejando que alguien inyectase cdigo javascript en tu pgina, y como vemos en este ejemplo, eso significa que podran entre otras cosas robar cookies del navegador de otros usuarios asociadas a tu sitio y potencialmente suplantarles en el futuro. Para evitar este tipo de ataques Grails proporciona codecs que permiten escapar valores para usarlos en HTML, URLs, entre otros usos. Por tanto la forma correcta de mostrar los comentarios sera esta: Eh >ComentariosE@h > Eg1each in7^$6comentarios;^> Ediv class7^comentario^> $6it.te3to.encodeAsF2)#; E@div> E@g1each> El mtodo encodeAsF2)# sustituye todos los caracteres de nuestra cadena que tienen algn significado en HTML, como < y > por secuencias equivalentes como &lt; y
Pgina 160

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

&gt;

Codecs
Como ya hemos visto, en Grails podemos utilizar los mtodos encodeAsF2)# y encodeAs0.# para evitar caracteres ilegales. De forma ms general, un codec es una utilidad que permite representar un objeto en un formato especial. En Grails, los codecs son clases cuyo nombre termina en Codec y que se alojan en la carpeta grails-app@utils de nuestro proyecto. Si creamos una clase que cumpla esta convencin, y que adems contenga una closure con el nombre encode y/o decode, Grails automticamente aadir mtodos dinmicos a la clase Object para codificar y descodificar cualquier cosa. Por ejemplo, si creamos una clase grailsapp@utils@)i4ormatoCodec.groov( as: class )i4ormatoCodec 6 def encode 7 6b; ; Entonces podremos invocar el mtodo encodeAs)iformato() sobre cualquier objeto de nuestra aplicacin. Grails incluye de forma estndar una serie de codecs que resuelven muchas de las situaciones ms habituales: F2)#Codec permite escapar y des-escapar los caracteres especiales en un texto para que no incluya etiquetas HTML. 0.#Codec permite incluir el texto en una URL, escapando todos los caracteres ilegales. 5aseDMCodec codifica y descodifica Base64 -ava"criptCodec codifica strings escapando caracteres ilegales en javascript. Fe3Codec codifica un array de bytes o una lista de enteros en un string de valores hexadecimales. ):=Codec codifica un array de bytes, una lista de enteros o una cadena de texto, como un hash MD5 en un string. ):=5(tesCodec igual que el anterior, pero devolviendo el array de bytes en lugar del string. "FA Codec codifica un array de bytes, una lista de enteros o una cadena de texto, como un hash SHA1 en un string. "FA 5(tesCodec igual que el anterior, pero devolviendo el array de bytes en lugar del string. "FAK=DCodec codifica un array de bytes, una lista de enteros, o una cadena de texto, como un hash SHA256 en un string.

Pgina 161

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

"FAK=D5(tesCodec igual que el anterior, pero devolviendo el array de bytes en lugar del string.

Pgina 162

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

17. < sarro!!o d

P!ugins

Pgina 163

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

A lo largo del libro hemos estado hablando de cmo el sistema de plugins de Grails permite ampliar la funcionalidad de nuestras aplicaciones de forma sencilla. Existen extensiones para muchas de las situaciones ms habituales: Integracin de tareas programadas: QuartzPlugin . Gestin de usuarios, autorizacin y autenticacin: SpringSecurity . Integracin de motor de indexacin: SearchablePlugin . Generacin de scaffolding en Flex: Flex Scaffold. Pruebas funcionales: WebTestPlugin. Gestin de archivos de vdeo: VdeoPlugin. Servicios web SOAP: SpringWS. Soporte para Google AppEngine: AppEnginePlugin. etc. Te recomiendo que eches un vistazo a la lista completa de plugins disponibles que puedes encontrar en la web oficial: http://grails.org/plugin/home.

Pgina 164

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pero, aparte de incorporar funcionalidades definidas por otros, un aspecto muy importante del sistema de extensiones de Grails es que permite disear aplicaciones de forma modular, aumentando la calidad de nuestro software en general. Si llevas tiempo desarrollando aplicaciones, sabrs que un porcentaje muy grande del cdigo en una aplicacin es genrico. Cuestiones como la gestin de usuarios y permisos, la publicacin de documentos en distintos formatos, la generacin de informes, entre otras, se implementan de forma similar en todas las aplicaciones, cuando no son simplemente copiadas entre proyectos. Por eso, si empiezas a ver tus aplicaciones como mdulos interconectados en lugar de como bloques monolticos, te dars cuenta de la cantidad de cdigo que puedes reutilizar entre proyectos. Para ilustrar el desarrollo de plugins con Grails vamos a crear dos extensiones diferentes. En la primera veremos cmo hacer que el plugin aada artefactos a la aplicacin en la que lo instalemos. El segundo te mostrar como aadir mtodos dinmicos a las clases de la aplicacin.

Qupodemoshaceren un plugin?
Como hemos visto, un plugin puede aportar artefactos nuevos a una aplicacin. Los tipos de artefactos disponibles son: Controladores Libreras de tags Servicios Vistas Plantillas

Adems, un plugin tambin puede alterar el funcionamiento de la aplicacin de varias formas: Respondiendo a eventos Grails (cambio de versin, instalacin del plugin, etc). Alterando la configuracin de Spring (definiendo nuevos beans que estarn disponibles en el contenedor). Modificando la generacin del archivo web.xml. Aadiendo mtodos dinmicos a las clases de la aplicacin. Monitorizando los cambios de ciertos componentes. Tienes mucha ms informacin sobre las posibilidades en el desarrollo de plugins en la documentacin oficial: http://grails.org/doc/1.1/guide/12.%20Plug-ins.html
Pgina 165

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Tu primerplugin:aadirartefactosa la aplicacin.
En Grails, un plugin no difiere mucho de una aplicacin. Para comenzar el desarrollo de un plugin ejecutamos el comando: grails create-plugin e,emplo Este comando crear un proyecto con la misma estructura que una aplicacin, ms un archivo en la raz del proyecto con el nombre (en este caso) E,emplo+railsClugin.groov(, que contiene la descripcin de nuestro plugin: class E,emplo+railsClugin 6 def version 7 A>. A def grails'ersion 7 A . def depends*n 7 819 def pluginE3cludes 7 8 Agrails-app@vie&s@error.gspA 9 @@ 2*:* 4ill in these fields def author 7 AOour nameA def authorEmail 7 AA def title 7 AClugin summar(@headlineA def description 7 GGGYY 5rief description of the plugin. GGG def documentation 7 Ahttp1@@grails.org@E,emplo+CluginA def doLith"pring 7 6 ; def doLithApplicationConte3t 7 6appConte3t -> ; def doLithLeb:escriptor 7 6 3ml -> ; def doLith:(namic)ethods 7 6 ct3 ->
Pgina 166

> NA

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

; def onChange 7 6 event -> ; def onConfigChange 7 6 event -> ; ; Nuestro trabajo consistir en definir en este archivo cmo el plugin va a alterar el funcionamiento de la aplicacin en la que se instale, ya sea aadiendo artefactos (entidades, controladores, etc) registrando nuevos mtodos dinmicos en las clases, o interceptando los eventos que se producen a lo largo del ciclo de vida del proyecto para alterar la generacin del archivo web.xml o de la configuracin de Spring. En este caso vamos a haremos que el plugin incorpore una etiqueta nueva a las aplicaciones sobre las que se instale. Cuando se incluya la etiqueta en una GSP permitir enviar el cuerpo por correo electrnico: Ei&1email to7GnachoJimagina&orHs.comG sb,7GpruebaG> Ep> Cuerpo del mensa,e en Estrong>htmlE@strong> E@p> E@i&1email> Comenzamos el desarrollo creando el proyecto, que llamar iwMail: grails create-plugin i&)ail Una vez creado el proyecto, lo primero que necesitamos es un servicio para enviar correo electrnico, as que ejecutamos: grails create-service email y rellenamos el archivo grails-app@services@Email"ervice.groov(, suponiendo que tenemos una clase com.imagina&orHs.srvc.Email que hace el trabajo (es fcil desarrollar esa clase utilizando, por ejemplo, commons Email de Apache): import org.apache.commons.logging.#og4actor( import com.imagina&orHs.srvc.email.Email class )ail"ervice 6 boolean transactional 7 false
Pgina 167

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def sendF2)#( "tring smtpI "tring fromI "tring toaddressI "tring contentI "tring msg"ub,ect) 6 log.info(AEnviando correo desde $6from; a $ 6toaddress;. Asunto1 $6msg"ub,ect;I Cuerpo1Yn$ 6content;A) tr(6 Email.sendF2)#Email( smtpI usrI p&dI fromI toaddressI msg"ub,ectI &rapLithFtml(content) )] ; catch(E3ception 3)6 log.error(AError al enviar el correo1 $63;A) 3.print"tacH2race()] ; ; def &rapLithFtml(msg) 6 def &rapped 7 AAA Ehtml> Ehead> Est(le> bod( 6 color1 c<<<] font-si/e1 >.!em] line-height1 .!em] te3t-align1 left] bacHground-off1 cEDEDED] ; E@st(le> E@head> Ebod(> $6msg; E@bod(> E@html> AAA return &rapped ; ;
Pgina 168

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El servicio que acabamos de definir tiene, por un lado, un mtodo pblico sendF2)# que utiliza la clase Email para hacer el envo del correo electrnico. Y por otro, un mtodo auxiliar que encuadra el cuerpo del mensaje en una plantilla fija. Lo siguiente que haremos es crear la librera de etiquetas: grails create-tag-lib email Y completar el archivo grails-app@taglib@Email2ag#ib.groov(: class Email2ag#ib 6 static namespace 7 Gi&G )ail"ervice mail"ervice def email 7 6attrsI bod( -> def smtp 7 Gservidor.correo.smtpG def from 7 G&ebmasterJe,emplo.comG tr(6 mail"ervice.sendF2)#( smtpI fromI attrs.toI bod(()I attrs.sb,) ; catch(E3ception 3)6 log.error(AE..*.1 $63;A) ; ; ;

Observa que el nombre de la closure email es lo que tendremos que usar para invocar la etiqueta desde GSP: <iw:email > ...</iw:email>, usando el espacio de nombres iw tal como lo hemos definido en la propiedad esttica namespace. Puesto que un plugin es un tipo particular de aplicacin Grails, podemos ejecutarlo en cualquier momento mediante grails run-app para evaluar el funcionamiento de cada componente, y por supuesto disear nuestras bateras de pruebas etc. Con esto tenemos ya todo lo que necesitamos en nuestro plugin. Ahora veamos cmo empaquetarlo y ponerlo a disposicin del mundo o de nuestro propio equipo de desarrollo.

Pgina 169

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Distribuirel plugin
Una vez terminado el desarrollo, necesitamos empaquetar el plugin para que pueda ser distribuido: grails pacHage-plugin Este comando crear un archivo Zip con el contenido de nuestro plugin excepto: grails-app@conf@:ata"ource.groov( grails-app@conf@0rl)appings.groov( build.3ml &eb-app@LE5-PB4@NN Estos archivos se excluyen en el empaquetado, porque definen cuestiones como el acceso a datos que no son responsabilidad del plugin sino de la aplicacin en la que los instalemos. Se crearon nicamente para que pudiramos probar el proyecto durante la fase de desarrollo. El proceso crear por tanto un archivo con el nombre grails-[nombre]-[version].zip, en este caso grails-i&-mail->. ./ip.
Recuerda que puedes modificar el nmero de versin de tu aplicacin / plugin con el comando grails set-version.

Desde el momento en que est generado el archivo, podemos instalarlo en cualquier aplicacin Grails mediante el comando grails install-plugin @ruta@a@grails-i&-mail->. ./ip Tambin podemos publicarlo en un servidor web e instalarlo con: grails install-plugin http1@@mi&eb.com@plugins@grails-i&-mail->. ./ip Por ltimo, si pensamos que nuestro plugin resuelve un problema comn y tiene la calidad suficiente como para que otros puedan beneficiarse de l, podemos publicarlo en el el repositorio oficial. Para ello deberemos ponernos en contacto con el equipo de desarrolladores de Grails para que nos den acceso al repositorio central, y despus ejecutar el comando grails release-plugin que realizar el trabajo de publicacin.

Quocurrecuandoinstalamosun pluginen unaaplicacin?


Para instalar un plugin en una aplicacin Grails debemos ejecutar el comando install-plugin. Al Hacerlo, Grails extraer el contenido del archivo ZIP en un
Pgina 170

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

directorio central dentro de tu carpeta de usuario ($F*)E@.grails@ 8version9@pro,ects@8aplicacin9@plugins@) y pondr a disposicin de tu aplicacin los artefactos definidos en el plugin. El cdigo fuente del plugin nunca se mezcla con el de la aplicacin, de forma que no interferir con tu proceso de desarrollo. Cuando generes el archivo war de tu aplicacin, Grails compilar todas las clases Groovy y Java del plugin y colocar los archivos .class en WEB-INF/classes junto con los de tuyos. Es muy importante que tengas en cuenta que si tu plugin incluye contenido esttico (imgenes, archivos javascript, hojas de estilo, etc), Grails los copiar en la carpeta &eb-app@plugins@8tu plugin9 del proyecto, lo cual afectar a la hora de crear enlaces a dichos recursos. Para evitar problemas puedes utilizar la variable pluginConte3tCath en tus enlaces y rutas: Eg1resource dir7G$6pluginConte3tCath;@,sG file7Gutils.,sG @>

Tu segundoplugin:aadirmtodosdinmicosa las clasesde la aplicacin.


Ahora que nos hemos adentrado en el desarrollo de plugins, vamos a ver un ejemplo algo ms avanzado. Como hemos comentado, los plugins nos permiten aadir artefactos a nuestra aplicacin, pero tambin pueden modificar los artefactos existentes. En particular, podemos aadir mtodos dinmicos a cualquier clase que exista en nuestra aplicacin. Para explorar esta caracterstica, desarrollaremos una extensin que aada a las clases de entidad un mtodo toC"'.o& que permita obtener una representacin de cada instancia en el formato CSV (valores separados por comas), y un mtodo esttico csvFeader que permita generar el encabezado del CSV con los nombres de las columnas. De esta manera, cualquier aplicacin en la que instalemos el plugin dispondr de la funcionalidad necesaria para generar listados de entidades en texto por columnas, muy apropiado si necesitamos llevarlos a una hoja de clculo. Lo primero que tendremos que hacer, igual que en el ejemplo anterior, es crear el plugin: grails create-plugin csvClugin Una vez creado el proyecto, editaremos el archivo CsvClugin+railsClugin.groov( para aadir en la closure doWithDynamicMethods el cdigo necesario para modificar las entidades:
Pgina 171

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def doLith:(namic)ethods 7 6 ct3 -> for (gdc in application.domainClasses) 6 @NN )Stodo estTtico para escribir la cabecera del C"' NN@ gdc.meta'lass.'static'.cs)/eader = {0b1ect23 args 45 de# cs) = '' gdc.persistent6roperties.each{ cs) 7= 89{it.name},8 } cs) = cs)2-..cs).si:e+. 4 23 7 ';n' return cs) } @NN )Stodo de instancia para convertir un ob,eto en una fila C"' NN@ gdc.meta'lass.to'(<=o& = { 0b1ect23 args 45 de# cs) = '' de# )alue gdc.persistent6roperties.each{ )alue = delegate.89{it.name}8 cs) 7= 89{)alue},8 } cs) = cs)2-..cs).si:e+. 4 23 7 ';n' return cs) } ; ; De esta forma, al inicializar el plugin estaremos recorriendo todas las clases de entidad definidas en la aplicacin y aadiendo dos mtodos, uno esttico y otro de instancia. Esta tcnica es posible gracias a que cada plugin tiene acceso a una implementacin de la interfaz +railsApplication que, entre otras cosas, nos da acceso a los distintos artefactos mediante una serie de propiedades dinmicas (al estilo de los dynamicFinders de GORM): *Classes obtiene todas las clases para un tipo particular de artefacto. get*Class localiza el artefacto por su nombre (ej get:omainClass(gCersona^)) is*Class comprueba si una clase es un tipo particular de artefacto.
Pgina 172

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

add*Class aade un artefacto a la aplicacin, devolviendo una referencia a l para poderlo manipular. En cada caso el asterisco se podr sustituir por todos los tipos de artefactos: controller domain taglib service Por ejemplo, podemos acceder a los controladores de nuestra aplicacin mediante la propiedad dinmica controllerClasses: application.controllerClasses.each 6println it.name; Una vez que tenemos la instancia de la clase, usamos las herramientas de Groovy para programacin dinmica. Cuando hacemos gdc.metaClass.toC"'.o& 7 6b; estamos usando la metaclase que Groovy asocia a cada clase Java en tiempo de ejecucin, y que nos permite aadir mtodos y acceder a las propiedades de forma dinmica, entre otras cosas. En el cuerpo del mtodo que definimos podemos acceder al objeto sobre el que se est ejecutando el mtodo mediante la variable delegate, como puede verse en el mtodo toC"'.o&. Con esto terminamos el plugin. Solo falta empaquetarlo con: grails pacHage-plugin y tendremos nuestro archivo grails-csv-plugin->. ./ip listo para instalar en cualquier aplicacin con grails install-plugin @ruta@a@ grails-csv-plugin->. ./ip Cuando lo hagamos, podremos hacer en la aplicacin cosas como esta: class #ibroController 6 def listAsC"' 7 6 def l 7 #ibro.list(params) def csv 7 #ibro.csvFeader() l.each6 csv +7 it.toC"'.o&() ;
Pgina 173

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

render(content2(pe1Gte3t@csvGIte3t1csv) ; ; La ventaja de este sistema evidente: podemos encapsular en plugins funcionalidades transversales y reutilizarlas en todas nuestras aplicaciones. Adems, podemos dividir proyectos grandes en mdulos ms asequibles de manera que la organizacin del equipo de trabajo sea ms clara. Por tanto, no deberamos ver los plugins de Grails nicamente como una forma de extensin del framework, sino como un recurso muy valioso desde el punto de vista de la arquitectura de nuestras propias aplicaciones.

Pgina 174

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

18. % r;icios 2 ) con "rai!s4 %/*P ;s 0.%B

Pgina 175

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Segn la Wikipedia, un servicio web es un conjuntode protocolosy estndaresque sirvenpara intercambiardatosentre aplicaciones . La idea es definir mecanismos de comunicacin que sean sencillos de implementar e independientes de la plataforma de forma que, por ejemplo, un cliente desktop escrito en VisualC# pueda consumir un servicio implementado en Java. Lo ms habitual en los ltimos aos es que estos servicios se construyan sobre el protocolo HTTP de forma que la plataforma de comunicacin es la misma que utiliza un navegador web para comunicarse con el servidor. Existen diferentes estndares que especifican la forma definir servicios web sobre HTTP, de forma que a la hora de desarrollar servicios web con Grails, igual que con cualquier otro entorno, tenemos que decidir por el estndar a utilizar. A da de hoy podramos, simplificando, resumir las opciones en dos: SOAP(SimpleObject AccessProtocol ) es un estndar del W3C que define cmo objetos remotos pueden comunicarse mediante el intercambio de XML. La idea bsica es que en la comunicacin hay dos partes (cliente y servidor), una de las cuales (el servidor) presta una serie de servicios que son consumidos por la otra (cliente). Lo ms habitual es que el servidor haga pblica la especificacin de sus servicios mediante un documento WSDL (WebServiceDescriptionLanguage ) que podemos utilizar construir un cliente que invoque tales servicios. Lo importante aqu es entender que los servicioswebSOAPestnorientadosa funcionalidad . El servidor implementa una serie de funcionalidades y le dice al mundo cmo pueden invocarse. REST(RepresentationalState Transfer ) es un conjunto de tcnicas orientadas a crear servicios web en los que se renuncia a la posibilidad de especificar la interfaz de los servicios de forma abstracta a cambio de contar con una convencin que permite manejar la informacin mediante una serie de operaciones estndar. La convencin utilizada no es otra que el protocolo HTTP. La idea detrsde RESTes el desarrollode serviciosorientadosa la manipulacinde recursos . En un servicio REST tpico, tenemos una URL por cada recurso (documento, entidad, etc) que gestionamos, y que realiza una tarea diferente sobre dicho recurso en funcin del mtodo HTTP que utilicemos.

La diferencia entre ambos sistemas se ver muy clara con un ejemplo. Supongamos que necesitamos desarrollar un servicio web para manipular los registros de tipo Persona de nuestra aplicacin. El servicio debe ser capaz de realizar las tpicas operaciones CRUD: Creacin, Lectura, Actualizacin y Borrado.

UsandoSOAP
Grails no soporta SOAP de fbrica, aunque existen varios plugins que podemos usar entre los cuales quiz el ms maduro sea XFire Plugin.

Pgina 176

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

UsandoXFire
XFirePlugin(http://www.grails.org/plugin/xfire) permite exponer los servicios Grails como servicios web SOAP. Una vez instalado mediante el comando grails install-plugin 3fire, tendramos que crear un servicio que implementase la lgica de manipulacin de nuestras entidades Persona: grails create-service personas class Cersonas"ervice 6 static e3pose78G3fireG9 void altaCersona(Cersona p)6 @@implementacin ; void ba,aCersona(#ong id)6 @@implementacin ; @@etc... ; Como habrs notado, hemos aadido una propiedad esttica expose en el servicio. ste marcador hace que el plugin de Xfire sea capaz de generar el WSDL de forma automtica en la siguiente URI: @services@personasW&sdl Esta especificacin podra usarse para generar un cliente que accediese al servicio.

UsandoREST
Para crear el servicio mediante REST no necesitamos ningn plugin. Como hemos comentado, se trata de un estndar en el que la interfaz est bien definida en el propio protocolo HTTP, y los datos de entrada y salida se representan mediante XML sencillo (POX, o Plain Old XML ). Para entender a fondo el desarrollo REST con Grails te recomiendo el artculo de Scott Davis RESTful Grails publicado en DeveloperWorks dentro de la serie Mastering Grails. Lo puedes consultar en sta direccin: http://www.ibm.com/developerworks/library/j-grails09168/ Por tanto, para crear nuestro servicio CRUD lo que necesitamos es definir una URL nica por cada Persona (por ejemplo, @persona@rest), e implementar la funcionalidad asociada a cada mtodo HTTP: GET Se usa para consultas. Una invocacin GET a la url @persona@rest@= tendr que devolver una representacin en XML de la persona con id 5.

Pgina 177

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

POST Se usa para altas. Una invocacin POST a @persona@rest deber contener la representacin XML de la persona que queremos registrar. PUT Se usa para actualizaciones. Una invocacin PUT a la url @persona@rest@= deber contener los datos que deseamos modificar en persona con id 5. DELETE Se usa para bajas. Una peticin DELETE a la url @persona@rest@= dar de baja la persona con id 5. Como ves, las interfaces REST se construyen sobre un convenio ampliamente extendido basado en el protocolo sin estado HTTP. Grails cuenta con dos herramientas que facilitan enormemente el desarrollo de servicios web, en particular si son de tipo REST: Conversina XMLautomtica El XML Converter (grails.converters.XML) es capaz de generar POX a partir de prcticamente cualquier estructura de datos. Gracias a ello, si no necesitamos un XML con un formato especfico, podemos generar nuestras respuestas en una sola lnea. Procesadode XMLautomtico Si fijamos el tipo mime de nuestra peticin a text/xml, Grails procesar el XML que pongamos en el cuerpo y lo colocar en nuestro params como una estructura de datos (en realidad lo que tendremos ser un objeto XmlSlurper).

ClientesRESTparapruebas
Para probar nuestro servicio REST necesitamos algn cliente que sea capaz de enviar peticiones HTTP mediante todos los mtodos. Los navegadores habitualmente slo soportan GET y POST. Las dos opciones ms interesantes son el rest-client de WizTools.org, y Poster, un plugin para Firefox.

Pgina 178

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

UsandoPoster
Poster es un complemento para Firefox pensado especficamente para probar servicios web. Podis instalarlo directamente desde el navegador (Men Herramientas > Complementos) o desde la web: https://addons.mozilla.org/en-US/firefox/addon/2691

Pgina 179

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 180

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 181

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 182

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 183

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 184

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 185

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 186

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 187

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 188

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 189

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 190

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 191

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 192

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Usandorest-client
Rest-client es una aplicacin Swing que podemos utilizar para probar servicios web. Incluye el entorno de ejecucin de Groovy, de forma que podemos escribir scripts para probar nuestros servicios e la propia interfaz. Definitivamente es un proyecto al que deberas echar un vistazo: http://code.google.com/p/rest-client/

Pgina 193

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 194

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Implementandoel servicio
Suponiendo que ya tenemos definida la clase Persona (una entidad normal y corriente), crearamos un controlador con el mismo nombre (suponemos que no hemos creado el scaffolding, o bien que estamos usando el mismo servidor para todo): import grails.converters.[)# class CersonaController 6 def rest 7 6 s&itch(re%uest.method)6 case G+E2G1 do+et(params) breaH] case GC*"2G1 doCost(params) breaH] case GC02G1 doCut(params) breaH] case G:E#E2EG1 do:elete(params) breaH] ; ;

... ;

Como ya vimos en el captulo 8, en los controladores tenemos acceso al objeto request que nos da, entre otras cosas, el mtodo utilizado en la peticin. Gracias a esto podemos implementar distintos mtodos para tratarla en funcin del mtodo HTTP utilizado. Fjate en el import de grails.converters.[)#, que necesitaremos para generar todas las respuestas. Veamos ahora la implementacin de los distintos mtodos:

ProcesarpeticionesPOST
private void doCost(params)6 def p 7 ne& Cersona(params.persona) if(p.save())6 render p as [)# ; else6 response.status 7 =>> render p.errors as [)# ; ;
Pgina 195

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El mtodo doCost es el encargado de tratar peticiones de alta. Como ves, si enviamos contenido XML mediante POST, y fijamosel tipo mimede la peticina te*t/*ml, Grails procesa el XML y lo coloca, como un Map, en el atributo correspondiente. Aqu tienes la peticin y la respuesta usando rest-client:

Este sistema funciona perfectamente y es sencillo de implementar, aunque para poder hacerlo as es necesario que podamos definir nosotros el esquema del XML de la peticin. Si no podemos hacerlo, tambin existe la posibilidad de tratar el XML a mano: private void doCost(params)6
Pgina 196

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def p 7 ne& Cersona() def d 7 re%uest.[)# p.nombre 7 d.nombre p.apellidos 7 d.apellidos p.codigoEmpleado 7 d.codigoEmpleado if(p.save())6 render p as [)# ; else6 response.status 7 =>> render p.errors as [)# ; ;

ProcesarpeticionesGET
El mtodo doGet es el responsable de las consultas: private void do+et(params)6 def p 7 Cersona.get(params.id) render p as [)# ; Como ves, una vez ms estamos devolviendo el objeto persona como XML usando el converter por defecto:

Pgina 197

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Si necesitamos generar XML con una estructura distinta, podemos utilizar el mtodo render tal como vimos en el captulo 8: private void do+et(params)6 def p 7 Cersona.get(params.id) @@render p as [)# render(content2(pe1Gte3t@3mlG)6 personas 6 persona6 cdigo(p.codigoEmpleado) nombreCompleto( A$6p.apellidos;I $6p.nombre;A) ; ; ; ; El resultado en este caso ser:

Pgina 198

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ProcesarpeticionesPUT
El mtodo doPut deber procesar peticiones de actualizacin de datos: private void doCut(params)6 def p 7 Cersona.get(params.id) p.properties 7 params.persona if(p.save())6 render p as [)# ; else6 response.status 7 =>> render p.errors as [)# ; ;

Pgina 199

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ProcesarpeticionesDELETE
El ltimo mtodo a implementar es doDelete, que debe gestionar la peticiones de borrado: private void do:elete(params)6 def p 7 Cersona.get(params.id) p.delete() render(content2(pe1Gte3t@3mlG)6 resultado( ACersona con id $6params.id; borrada correctamente.A ) ; ; Y con esto terminamos nuestro servicio REST sobre las entidades Persona. Lgicamente, en una aplicacin de la vida real necesitaramos algo ms de lgica, por ejemplo para verificar la identidad de quien invoca, o para validar los datos de entrada.
Pgina 200

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

An as, espero haberte convencido de lo sencillo que resulta realizar un desarrollo de este tipo con Grails.

ServiciosRESTcompatiblesconJAXRS
Desde Octubre de 2008 existe un JSR (Java Specification Request) que estandariza el API para implementar servicios REST en la plataforma Java. Se trata del JSR 311: JAX-RS (Java API for RESTful Web Services), cuyo objetivo es, segn figura en el propio documento, proporcionara los desarrolladoresun API de alto nivel y fcil de usar para escribir servicioswebRESTfulindependientesdela tecnologasubyacente,y permitir que estosservicios funcionensobrela plataformaJavaEE o Java SE. Existe un plugin que permite desarrollar servicios REST compatibles con el JSR 311 en Grails. Se trata de grails-jaxrs, que podemos encontrar en Google Code. Una vez instalado, el plugin introduce dos tipos nuevos de artefactos en nuestra aplicacin: Recursos(Resource), que representan la informacin expuesta mediante el servicio REST, y son clases cuyo nombre termina en .esource y se alojan en grailsapp@resources. Proveedores(Provider), que permiten personalizar la representacin de nuestras entidades en XML. Son clases cuyo nombre termina en Crovider y se alojan en grails-app@providers. Para implementar un servicio REST alrededor de una entidad de nuestro modelo de datos, el plugin nos proporciona el script generate-resources, que genera los recursos necesarios para realizar las operaciones POST, GET, PUT y DELETE del protocolo HTTP: grails generate-resources persona Una vez ejecutado, podremos arrancar la aplicacin y utilizar la uri /8aplicacion9@persona para operar sobre las entidades de este tipo, y @8aplicacion9@persona@8P:9 para operar sobre una instancia en particular. El script generate-resources crea dos recursos para cada entidad, en el caso de Persona sern: grails-app/resources/PersonaCollectionResouce.groovy: import static org.grails.,a3rs.response..esponses.N import import import import import ,ava3.&s.rs.+E2 ,ava3.&s.rs.Croduces ,ava3.&s.rs.Cath ,ava3.&s.rs.CathCaram ,ava3.&s.rs.C*"2
Pgina 201

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

import ,ava3.&s.rs.core..esponse JCath(G@personG) JCroduces(Gte3t@3mlG) class CersonaCollection.esource 6 JC*"2 .esponse create()ap properties) 6 created ne& Cersona(properties).save() ; J+E2 .esponse readAll() 6 oH Cersona.findAll() ; JCath(G@6id;G) Cersona.esource get.esource(JCathCaram(GidG) "tring id) 6 ne& Cersona.esource(id1id) ; ; grails-app/resources/PersonaResource.groovy: import static org.grails.,a3rs.response..esponses.N import import import import import ,ava3.&s.rs.:E#E2E ,ava3.&s.rs.+E2 ,ava3.&s.rs.Croduces ,ava3.&s.rs.C02 ,ava3.&s.rs.core..esponse

JCroduces(Gte3t@3mlG) class Cersona.esource 6 def id J+E2 .esponse read() 6 def ob, 7 Cersona.get(id) if (ob,) 6 oH ob, ; else 6 not4ound Cersona.classI id ; ; JC02
Pgina 202

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

.esponse update()ap properties) 6 def ob, 7 Cersona.get(id) if (ob,) 6 ob,.properties 7 properties oH ob, ; else 6 not4ound Cersona.classI id ; ; J:E#E2E void delete() 6 def ob, 7 Cersona.get(id) if (ob,) 6 ob,.delete() ; ; ;

Pgina 203

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

19. .ntornos d

d sarro!!o

Pgina 204

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

A la hora de buscar un IDE (IntegratedDevelopmentEnvironment , o Entornode Desarrollo Integrado ) con el que trabajar en Groovy y Grails, debes tener en cuenta que existen grandes diferencias entre los lenguajes estticos y dinmicos respecto a lo que un entorno integrado te puede ofrecernos. Cuando trabajamos en lenguajes de tipado esttico como Java, los IDEs pueden compilar el cdigo a medida que lo escribimos para avisarnos de los fallos de sintaxis que cometamos, el uso de tipos de datos incorrectos as como de los errores en nombres de mtodos o clases. Tambin dispondremos de ayudas como el autocompletado de nombres de variables y de propiedades y mtodos disponibles para un objeto:

En Groovy (y en cualquier lenguaje dinmico), un IDE slo puede avisarnos con absoluta certeza de los errores de sintaxis. Respecto a los tipos de datos y las propiedades y mtodos que tendrn los objetos lo mejor que puede hacer es intentar predecirlo o proponernos una lista genrica:

Pgina 205

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

En este captulo haremos un repaso por los entornos de desarrollo ms populares, revisando su soporte para Groovy y Grails. Para organizar la tarea, repartiremos los entornos en dos grandes familias: IDEs : Entornos de desarrollo integrales por derecho propio, que incluyen edicin de cdigo, compilacin y herramientas de soporte como depuracin o profiling. En esta categora encontramos a Netbeans, Eclipse e IntellyJIDEA. Editoresde texto : Son herramientas mucho ms limitadas en su funcionalidad, puesto que slo cuentan con resaltado de sintaxis y algunas ayudas ms como integracin de comandos de Grails, pero cuentan con la ventaja de consumir muchos menos recursos de la mquina y soportar gran nmero de lenguajes distintos. En esta categora hablaremos de UltraEdit , TextMate y E.

EntornosIntegrados
Netbeans(Gratuito)
Netbeans (www.netbeans.org) incluye soporte para Groovy y Grails desde la versin 6.5, incluyendo un tipo de proyecto y posibilidad de ejecutar comandos Grails desde el propio IDE. El soporte para Groovy incluye resaltado de sintaxis y autocompletado de nombres de variables y mtodos, y sigue evolucionando a muy buen ritmo.
Pgina 206

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Podemos crear cualquier tipo de artefacto desde el IDE sin tener que recurrir a la consola:

Pgina 207

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El editor de Groovy incluye autocompletado:

Pgina 208

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Incluso nos propondr los distintos mtodos dinmicos introducidos por GORM en nuestras entidades:

Netbeans nos propone los comandos adecuados para cada tipo de artefacto:

O podemos ejecutar cualquier comando pulsando con el botn derecho del ratn sobre el proyecto y eligiendo la opcin Run Grails Command:
Pgina 209

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

SpringSourceTool Suite (Basadoen eclipse,Gratuito)


A finales de Octubre de 2009 SpringSource liber la versin 2.2 de SpringSource Tool Suite (http://www.springsource.com/products/sts ), un IDE construido sobre Eclipse Europa, y que incorpora soporte para la mayora de los productos de la famila Spring: Spring Framework, Spring MVC, Spring ROO, y por su puesto, Grails.

Pgina 210

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

El entorno se descarga directamente desde la web de SpringSource, y consiste en un Eclipse Europa (v3.5.1) junto con algunas herramientas preconfiguradas como la integracin del API de VMWare, Maven y Web Tools Platform y varias extensiones ms desarrolladas por la compaa. Una vez instalado debemos instalar el soporte para Grails manualmente, ya que no viene incluido en la instalacin por defecto. Para ello, desde el STS Dashboard, que se abre automticamente al arrancar la herramienta pulsaremos sobre la pestaa Extensions para mostrar todas las opciones disponibles. El soporte para Grails ser la primera opcin, as que slo tendremos que marcarla y pulsar el botn Install en la parte inferior derecha:

Pgina 211

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Una vez termine la instalacin se nos recomendar que reiniciemos el IDE, tras lo cual podremos empezar a trabajar con Grails. En este punto debo aclarar que el soporte para Grails se encuentra en sus fases iniciales, y aunque es perfectamente operativo a da de hoy, quedan algunas aristas que es necesario pulir. Lo que podemos hacer, de momento es: Crear un proyecto de tipo Grails Application desde el asistente File > New > Other:

Pgina 212

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 213

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Ejecutar la aplicacin mediante un perfil de ejecucin de Eclipse:

Para ejecutar cualquier otro comando, tendremos que usar el perfil genrico Run as Grails Command...:

Pgina 214

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Respecto al editor de cdigo, parece algo ms fino que el de Netbeans a la hora de mostrar las opciones disponibles en un mbito concreto:

Pgina 215

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

IntelliJIDEA(205)
IDEA fue uno de los primeros IDEs en incorporar soporte para Groovy, cuando el soporte en Eclipse era muy precario y en Netbeans completamente inexistente. A partir de la versin 8, IDEA incorpora posiblemente el mejor soporte para Groovy y Grails sin necesidad de instalar complementos adicionales.

El soporte comprende un tipo de proyecto especfico para aplicaciones Grails, y reconocimiento de los distintos tipos de archivo incluidos. Podemos crear cualquier tipo de artefacto desde el explorador de archivos y editarlos en entornos con soporte para Groovy: autocompletado, resaltado de sintaxis y reconocimiento de tipo de artefacto.

Adems, el editor incorpora funciones interesantes, como accesos directos a funciones relacionadas con el archivo actual:

Pgina 216

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Incluso podemos generar diagramas Entidad-Relacin de nuestro modelo de datos:

(Imgenes tomadas de http://www.grails.org/IDEA+Integration )

Editoresde Texto
UltraEdit(49,95)
Ultraedit es un clsico entre los programadores que usan Windows. Comez como un reemplazo vitaminado del bloc de notas, pero ha evolucionado hasta convertirse en un potente editor multilenguaje. Entre las funcionalidades soportadas tenemos: Coloreado de cdigo. Ajuste de bloques de cdigo (smart-indent). Manejo de bloques de texto con el ratn (mover) o tabulador (indentar). Conversin de tipos de archivo y codificacin de caracteres. Vista hexadecimal. Macros. Comparacin de archivos.

Pgina 217

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

TextMate(48,75)
TextMate es un editor de texto para MacOSX. Entre sus principales ventajas tenemos: Integracin con la consola (escribiendo mate . En una shell abre el editor en modo proyecto para manejar los archivos de la carpeta actual). Buscar / Reemplazar en todos los archivos de un proyecto. Buscar / Reemplazar mediante expresiones regulares. Extensible mediante Bundles. Para Groovy y Grails tendremos: Resaltado de sintaxis. Indentacin de cdigo. Posibilidad de ejecutar comandos de Grails sin salir a la consola.

E Text Editor(34,95)
E es un remake de TextMate para Windows. La intencin del proyecto es implementar los mismos principios incluyendo la integracin con UNIX. Por eso al
Pgina 218

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

instalarlo se nos da la opcin de instalar tambin cygwin, una implementacin de la terminal de Linux para Windows. La gran ventaja de este proyecto es que, aunque es mucho ms reciente que TextMate, es compatible con su sistema de extensin mediante Bundles, por lo que el soporte para Grails en E es exactamente el mismo.

Pgina 219

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

*PEF<IC. *. Introduccin a "roo;=

Pgina 220

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

"Alrededor de 2004, James Strachan se encontraba en un aeropuerto con su mujer, esperando un avin que llegaba con retraso. Ella se fue de compras, as que l se meti en un Cibercaf y decidi espontneamente darse una vuelta por el sitio de Python y estudiar el lenguaje James es un programador Java experimentado, y a medida que revisaba las caractersticas de Python descubra las carencias de su lenguaje de programacin, como el soporte sintctico para operaciones habituales con tipos comunes, y sobre todo, la naturaleza dinmica. En ese momento surgi la idea de traer esas caractersticas a Java."

G"roo;= in *ctionG
Groovy es el lenguaje en el que se escriben las aplicaciones en Grails, o al menos la mayor parte de los artefactos que contienen. Por eso es importante que tengamos claros algunos conceptos sobre el lenguaje, su sintaxis, y sus posibilidades de integracin con libreras Java existentes.

El papelde Groovyen el ecosistemaJava


Groovy es un lenguaje nacido con la misin de llevarse bien con Java, vivir en la Mquina Virtual y soportar los tipos de datos estndar, pero aadiendo caractersticas dinmicas y sintcticas presentes en otros lenguajes como Python, Smalltalk o Ruby. Como veremos, el cdigo fuente Groovy se compila a bytecodes igual que Java, y es posible instanciar objetos Java desde Groovy y viceversa. Lo que Groovy aporta es una sintaxis que aumenta enormemente la productividad y un entorno de ejecucin que nos permite manejar los objetos de formas que en Java seran extremadamente complicado.

Descripcinrpidadel lenguaje
En general, el cdigo Groovy guarda bastante parecido con Java, lo que hace que la introduccin en el lenguaje sea sencilla para programadores familiarizados con l. La mayora de lo que hacemos en Java puede hacerse tambin en Groovy, incluyendo: :a s $aracin d ! cdigo n $a?u t s. < 1inicin d c!as s H 9c $to c!as s int rnasI = mJtodos. .structuras d contro!7 9c $to ! )uc! 1orHKKI. /$ rador s7 9$r sion s = asignacion s. 9c $cion s.

" stin d

Pgina 221

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

:it ra! s Hcon a!gunas ;ariacion sI Instanciacin7 r 1 r ncia = d Ar 1 r ncia d o)- tos7 !!amadas a mJtodosK Pero, adems, Groovy incluye mejoras sintcticas en relacin con: :a 1aci!idad d man -o d o)- tos7 m diant nu ;as 9$r sion s = sinta9is. <istintas 1ormas d d c!aracin d !it ra! s. Contro! d 1!u-o a;an6ado m diant nu ;as structuras. Fu ;os ti$os d datos7 con o$ racion s = 9$r sion s s$ c#1icas. .n "roo;= todo s un o)- to.
Por ejemplo, los paquetes groovy.lang, groovy.util, java.util, java.lang, java.net y java.io, as como las clases java.math.BigInteger y BigDecimal se importan automticamente.

Dr ; dad4 .! cdigo "roo;= s muc'o ms )r ; ?u ! d +a;a.

Qupinta tieneel cdigoGroovy?


Para empezar a estudiar la sintaxis bsica de Groovy, veamos el primer ejercicio, un Hola Mundo: Ejemplo1:HolaMundo.groovy @@Crimer e,emplo +roov(. def name7GnachoG println AFello $nameZA @@4in. A primera vista vemos que: Pod mos scri)ir scri$ts n !os ?u no 'a= c!as s H n r a!idad s# ?u !a 'a=7 $ ro no n c sitamos d c!arar!aI. Fo 'a= LKL a! 1ina! d !as !#n as. .n "roo;= s o$ciona!. :a $a!a)ra r s r;ada d 1 $ rmit d c!arar una ;aria)! d ti$o dinmico. Bam)iJn s $osi)! d c!arar ;aria)! s con ti$o sttico H -4 Int g r num roI :os com ntarios s cr an con MM o MN NM7 como n +a;a. $rint = $rint!n son ?ui;a! nt s a %=st m.out.$rint!nHI = %=st m.out.$rintHI7 r s$ cti;am nt . .! $arm tro a !a 1uncin $rint!n no ;a ntr $arJnt sis. .n "roo;=
Pgina 222

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

tam)iJn s o$ciona!.

Declaracinde clases
@ amos un - m$!o d d c!aracin d c!as 4 .- m$!o 2. C!as s.groo;= class Cersona 6 private "tring nombre private "tring apellido Cersona("tring nI "tring a)6 nombre 7 n apellido 7 a ; "tring to"tring()6 ACersona1 $nombre $apellidoA ; ; def p 7 ne& Cersona(GnachoGIGbritoG) def pK 7 8GnachoGIGbritoG9 as Cersona Cersona p< 7 8GnachoGIGbritoG9 /)s r;acion s4 %i no s$ ci1icamos !o contrario7 s cr arn !os g tt rs = s tt rs automticam nt .
Cuando el intrprete groovy detecte la necesidad de transformar una lista en un objeto, buscar en la clase un constructor que admita los objetos que contiene, en el mismo orden.

:a instanciacin $u d 'ac rs m diant !!amadas im$!#citas a! constructor. %i no usamos r turn n un mJtodo7 Jst d ;o!; r ! ;a!or d !a O!tima s nt ncia. Pod mos ins rtar ;aria)! s n cad nas d t 9to.

Scripts
Como hemos visto, el cdigo Groovy puede compilarse a bytecodes igual que Java, generando archivos .class que podemos ejecutar directamente en la Mquina Virtual. Existe adems otra forma de ejecutar el cdigo Groovy, que creando scripts y lanzndolos desde consola de igual forma que haramos con Python o Perl: Ejemplo3. Script1.groovy cZ@usr@bin@env groov( def p 7 8GnachoGIGbritoG9 as Cersona
Pgina 223

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

assert p.nombre 77 GnachoG assert p.apellido 77 GbritoG println p

GroovyBeans
Groovy facilita la creacin de JavaBeans gracias a que: Genera los getters y setters automticamente. Simplifica la sintaxis de acceso a propiedades. Simplifica el registro de auditores de eventos. Ejemplo4. Boton.groovy import ,ava3.s&ing.-5utton import ,ava3.s&ing.-Canel import ,ava3.s&ing.-4rame button 7 ne& -5utton(GCulsarG) button.actionCerformed 7 6 println button.te3t ; panel 7 ne& -Canel() panel.add(button) frame 7 ne& -4rame() frame.add(panel) frame.set'isible(true)

Cadenasde texto, expresionesregularesy nmeros


Groovy incorpora multitud de mejoras sintcticas para trabajar con texto, incluyendo las expresiones regulares. En Groovy las cadenas de texto pueden definirse con comillas dobles o simples. Las comillas simples crean cadenas constantes no modificables, mientras que las dobles permite la inclusin de variables dentro del texto y se evalan en tiempo de ejecucin. stas ltimas son instancias de la clase GString. A continuacin mostramos algunos ejemplos de lo que se puede hacer con GStrings: Ejemplo5: CadenasDeTexto.groovy s 7 AFola +roov(A println s println println println println println s.startsLith(GFolaG) @@true s.getAt(>) @@F s8>9 @@F s.contains(G+roov(G) @@true s8=.. >9 @@+roov(
Pgina 224

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

println println println println println

GFelloG + s - GFolaG @@Fello +roov( s.count(GoG) @@< G3G.pad#eft(<IGRG) @@RR3 G3G.center(<)@@ G 3 G G3GN< @@ 333

Respecto a las Expresiones Regulares, en Groovy encontramos tres operadores que permiten manejarlas de forma sencilla y eficaz: Operador de bsqueda: ~ Operador de coincidencia: ==~ Operador de patrn: ~String Ejemplo6: RegEx.groovy s 7 GCadena de pruebaG p 7 @e.a@ println s 77a p @@false c7> s.each)atch(p)6 c++ print A$itIA ; println A 2otal1 $c.A @@Escribe1 6AenaA;I6AebaA;I 2otal1 K.

Listas,mapasy rangos
+a;a7 como muc'os otros ! ngua- s7 so!o inc!u= so$ort Ha ni; ! d sinta9isI $ara un ti$o d co! ccin4 !os arra=s. .! r sto d co! ccion s s im$! m nta como o)- tos stndar. .n "roo;=7 9ist so$ort sintctico $ara !istas = ma$as7 = un ti$o d co! ccin ?u no 9ist n +a;a4 ! rango. .- m$!o 74 Co! ccion s.groo;= @@.angos1 def a 7 >.. > println a instanceof .ange @@true println a.contains(=) @@true def d 7 ne& :ate() def dK 7 d + K> for(d in (d ..dK)) println d @@#istas1 def l 7 8GtonoGIGtanoGIGtinoG9 def lK 7 ( .. >>).to#ist()]
Pgina 225

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

@@Adadir elementos1 l +7 GtunoG lK EE >> @@Acceder a los elementos println l println l 8>..K9 lK.each6 println it ; @@4iltrar l< 7 lK.findAll6 it Q K 77 > ; l<.each 6 println it ; @@)apas def m 7 8GunoG1 I GdosG1KI GtresG1<9 println m.uno @@ m.each6 println A$it.He(1 $it.valueA ;

Closures
:as c!osur s son uno d sos t mas ?u r su!tan di1#ci! s d nt nd r H= 9$!icarI cuando no s 'a o#do nunca so)r !!os7 $ ro una ; 6 asimi!ados s con;i rt n n una construccin d !o ms natura!. Dsicam nt 7 una c!osur s una ;aria)! cu=o ;a!or s un )!o?u d cdigo H$ar cido7 aun?u no 9actam nt igua!7 a un $unt ro a 1uncin d CI. :a gran ; nta-a d stas construccion s s ?u si m$r t ndrn acc so a! m)ito n ?u 1u ron cr adas7 aun?u s - cut n n otro distinto. Por - m$!o7 $od mos cr ar una c!osur n una 1uncin = $asar!a como $arm tro a otra 1uncin distinta7 ?u !a r ci)ir = - cutar. Pu s cuando s stJ - cutando n ! m)ito d !a s gunda 1uncin7 ! cdigo d !a c!osur s guir t ni ndo ;isi)i!idad so)r !as ;aria)! s !oca! s d !a $rim ra. .! conc $to d c!osur s asocia tradiciona!m nt con ! ngua- s structurados7 n !os ?u $od mos $asar cdigo como $arm tro a un mJtodo $ara ?u Jst !o - cut . .n !os ! ngua- s ori ntados a o)- tos s su ! Un ejemplo tpico de este patrn en Java es im$! m ntar sta 1unciona!idad m diant ! el mtodo Collections.sort(List l, Comparator c), donde c es una implementacin del $atrn /)- toA&Jtodo7 usando int r1ac s d mtodo compare(Object o1, Object o2); un s!o mJtodo = $asando instancias d c!as s ?u !a im$! m ntan7 $ ro st n1o?u s ms !imitado n r !acin con ! acc so a !as ;aria)! s7 = ad ms da !ugar a una sinta9is mu=
Pgina 226

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

com$! -a. "roo;= $ rmit d c!arar c!osur s d 1orma !im$ia = 1ica67 como ' mos ;isto n a!gunos d !os - m$!os ant rior s. % trata d )!o?u s d cdigo ?u $od mos $asar como $arm tros7 como ; r mos a continuacin4 .- m$!o 84 C!osur s.groo;= @@Closures1 .upto( >)6 println it ; def f 7 ne& 4ile("(stem.getCropert((Guser.homeG)) archivos7> b(tes7> f.each4ile.ecurse()6c -> archivos++ b(tes+7c.si/e() ; println A2u carpeta de usuario tiene $archivos archivos.A println AEl tamado total es de $b(tes b(tesA

En este ejemplo se ilustra adems el uso de algunos de los mtodos que Groovy aade a las clases del API estndar Java en tiempo de ejecucin. En el primer bloque usamos el mtodo upto(Closure) que se aade a todos los nmeros, y que permite una sintaxis muy expresiva para estructuras de repeticin. El segundo ejemplo usa el mtodo eachFileRecurse que Groovy aade a la clase File, y que permite obtener todos los archivos que hay dentro de una carpeta, recorriendo el rbol de directorios de forma recursiva. Ambos mtodos reciben una closure con el cdigo que queremos ejecutar sobre cada elemento de la coleccin intrnseca (los nmeros del 1 al 10 en el primer caso, los Objetos File en el segundo). En cada caso se utiliza la palabra reserva it para referirnos al objeto actual, o bien podemos declarar una variable para usar otro nombre (como en el segundo caso).

Estructurasde control
"roo;= so$orta !as mismas structuras d contro! ?u +a;a7 a 9c $cin d ! )uc! 1orHKKI7 incor$ora a!gunas otras ?u =a ' mos ;isto como ! mJtodo ac'HC!osur I ?u s incor$ora a $rcticam nt cua!?ui r ti$o ?u s $u d r corr r n +a;a H*rra=s7 Co! ccion s7 %trings7 0angos7 tcI. < todas 1ormas7 'a= ?u t n r n cu nta a!gunas di1 r ncias r s$ cto a +a;a a! tra)a-ar con structuras d contro! n "roo;=4 .n !as 9$r sion s condiciona! s nu!! s r tratado como 1a!s = notAnu!!
Pgina 227

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

como tru . :a s nt ncia s2itc' s $u d m$! ar so)r o)- tos d cua!?ui r ti$o.

Posibilidadesde integracinconlibrerasJavaexistentes
Como ya hemos comentado, !os scri$ts = !as c!as s "roo;= s - cutan n !a &?uina @irtua! +a;a7 = com$art n !os ti$os d datos d +a;a. ,n o)- to "roo;= s un o)- to +a;a7 r $r s ntado n m moria m diant )=t cod s n ti m$o d - cucin. *d ms7 !as c!as s +a;a son $ r1 ctam nt ;isi)! s d sd "roo;= = ;ic ; rsa7 !o cua! nos $ rmit d sarro!!ar a$!icacion s n !as ?u ! cdigo d uno = otro ! ngua- con;i;an d 1orma trans$ar nt . %i m$r 'a)r ! ngua- s ms ad cuados $ara r so!; r ci rto ti$o d $ro)! mas7 = !a 9ist ncia d "roo;= n !a &?uina @irtua! no $r t nd sustituir a +a;a sino com$! m ntars con J!. :a situacin id a! s r#a t n r ?ui$os 1ormados $or s$ cia!istas n uno = otro ! ngua- ?u im$! m ntas n distintos mdu!os d una a$!icacin con !as ' rrami ntas ms ad cuadas. ,na ; 6 com$i!ada !a a$!icacin todo star#a n !as !i)r r#as +*0 = 1uncionar#a como un todo.

Ejemplosde la vidareal:
A continuacin veremos algunos ejemplos prcticos que demuestran cmo la sintaxis de Groovy permite resolver problemas cotidianos de formas mucho ms elegantes.

TrabajarconXML
Groovy incorpora una construccin especfica para manera jerarquas de objetos: los builders. Se trata de una herramienta muy potente para crear y gestionar estructuras en rbol como las interfaces swing o los documentos XML. El siguiente ejemplo muestra cmo generar un documento XML mediante Groovy utilizando un objeto MarkupBuilder: Ejemplo9: Markup.groovy import groov(.3ml.)arHup5uilder &riter 7 ne& "tringLriter() builder 7 ne& )arHup5uilder(&riter) friendnames 7 8 ACacoAI A#olaAI AAndresA9 builder.persona() 6 nombre(nombre1A-osSAI apellidos1A:om$ngue/A) 6 edad(A<<A) genero(AmA) ;
Pgina 228

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

amigos() 6 for (e in friendnames) 6 amigo(e) ; ; ; println &riter.to"tring() El script anterior genera la siguiente salida por consola: Epersona> Enombre nombre7G-osSG apellidos7G:om$ngue/G> Eedad><<E@edad> Egenero>mE@genero> E@nombre> Eamigos> Eamigo>CacoE@amigo> Eamigo>#olaE@amigo> Eamigo>AndresE@amigo> E@amigos> E@persona>

TrabajarconSQL
El siguiente ejemplo ilustra cmo conectar con bases de datos usando JDBC. Adems, usa una librera Java, Commons Email, para enviar un correo electrnico. Se trata de un script que genera un listado de los artculos ms ledos de un portal y lo enva como adjunto en formato CSV a la direccin especificada. Para que el script funcione correctamente ser necesario que las libreras se encuentren en el CLASSPATH al ejecutarlo, para lo cual tendremos que copiar los archivos jar en la carpeta .groovy/lib del directorio HOME del usuario que lo lanza. Ejemplo10: SQL.groovy cZ@usr@bin@env groov( import groov(.s%l."%l import org.apache.commons.mail.N import ,ava.te3t."imple:ate4ormat def fecha 7 ne& "imple:ate4ormat(Add.)).((((A).format(ne& :ate()) def host 7 AlocalhostA def user 7 AdbuserA def pass 7 AdbpassA def schema 7 A+roov(FispanoA def driver 7 Acom.m(s%l.,dbc.:riverA def %uer( 7 A"E#EC2 idItituloIlecturas 4.*) stor( *.:E. 5O lecturas :E"C #P)P2 >I=>A] def remitente 7 Ano-repl(Jgroov(.org.esA def destinatario 7 AdestinatarioJservidor.comA def mailFost 7 Amail.servidor.comA

Pgina 229

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

def asunto 7 APnforme de lecturas1 $6fecha;A def informe 7 AP:I2P20#*I#EC20.A"YnA println AConectando con la base de datos...A s%l 7 "%l.ne&Pnstance(A,dbc1m(s%l1@@$6host;@$6schema;AI userI passI driver) println AConsultando...A s%l.each.o&(%uer(I6 informe +7 A$6it.id;I$6it.titulo;I$6it.lecturas;YnA ;) def tmp4ile 7 ne& 4ile(APnformeR$6fecha;.csvA) tmp4ile.&rite(informe) println AEnviando informe YA$6asunto;YA por correo a $ 6destinatario;A EmailAttachment attachment 7 ne& EmailAttachment()] attachment.setCath(tmp4ile.getCanonicalCath())] attachment.set:isposition(EmailAttachment.A22ACF)EB2)] attachment.set:escription(asunto)] )ultiCartEmail email 7 ne& )ultiCartEmail()] email.setFostBame(mailFost)] email.add2o(destinatario)] email.set4rom(remitente)] email.set"ub,ect(asunto)] email.set)sg(asunto)] email.attach(attachment)] email.send()] println A5orrando archivo temporalA tmp4ile.delete()] println ACroceso completadoA

TrabajarconFicheros
A continuacin se incluyen algunos ejemplos de trabajo con ficheros utilizando los mtodos que Groovy incorpora a la clase File: Ejemplo 11: Archivos.groovy @@#eer1 def t3t 7 ne& 4ile(Abuild.3mlA).get2e3t() println t3t @@"eleccionar1
Pgina 230

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ne& 4ile(G.@src@G).each4ile)atch(aA.NYY.groov(A)6f-> println f] ; @@Copiar ne& 4ile(Gbuild.t3tG).&ithLriter 6 file -> ne& 4ile(Gbuild.3mlG).each#ine 6 line -> file.&rite#ine(line) ; ; @@Adadir contenido1 d 7 ne& :ate() ne& 4ile(Glog.t3tG).append(A0ltima l$nea1 $dA)

Serviciosweb
El mdulo GroovyWS permite trabajar con servicios web de una forma mucho ms sencilla que los mecanismos tradicionales. Se trata de un mdulo independiente que debemos instalar aparte, aunque la instalacin consiste simplemente en copiar el archivo JAR en nuestra carpeta ~/.groovy/lib. Podemos descargarlo desde la direccin http://docs.codehaus.org/display/GROOVY/GroovyWS El siguiente ejemplo ilustra cmo consumir un servicio web:

Ejemplo12: SoapClient.groovy import groov(3.net.&s.L"Client def url 7 Ghttp1@@&&&.&ebservice3.net@Leather4orecast.asm3WL":#G def pro3( 7 ne& L"Client(urlIthis.class.class#oader) pro3(.create() def result 7 pro3(.+etLeather5(ClaceBame(A)adridA) println A#atitud1 $result.latitudeA println APmagen1 $result.detailsW.&eather:ata8>9W.&eatherPmageA Ejemplo13: SoapServer.groovy import groov(3.net.&s.L""erver class )ath"ervice 6 double add(double v I double vK) 6 return (arg> + arg ) ; double s%uare(double v) 6
Pgina 231

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

return (v N v) ; ;

def server 7 ne& L""erver() server.setBode(A)ath"erviceAI Ahttp1@@localhost1D?!>@)ath"erviceA)

Pgina 232

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 233

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

ImaginaCor3s7 mi m)ro 1undador d .scu !a d "roo;=


ImaginaWorks presta servicios de Formacin, direccin de proyectos, consultora y control de calidad en proyectos Grails a travs del proyecto Escuela de Groovy. Si necesitas servicios especializados no dudes en ponerte en contacto con nosotros: Informacin:902 546 336 / info@imaginaworks.com

Pgina 234

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Contro! d

; rsion s

Pgina 235

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

1.0 Versininicial pararevisin. Fecha: 15/05/2009 1.0.1 Primeraversincomercial. Fecha: 28/05/2009 Cambios:

Revisin sintctica y de estilo. Cap. 5 Aadido apartado sobre personalizacin de plantillas con install-templates.

1.0.2 Versincorregidaparaimpresin. Fecha: 1/06/2009 Cambios:

Re-maquetacin para mejorar compatibilidad con impresin a doble cara y encuadernacin.

1.0.3 Correccinde erratas Fecha: 01/06/2009 Cambios:

Fallo maquetacin en p. 77

1.0.4 Correccinde erratas Fecha: 09/06/2009 Cambios:


Errata en p. 50 Errata en p. 112

1.1.0 Primeraversinde la rama1.1 Fecha: 16/12/2009 Cambios:


Cambios en el formato, nueva portada. Correccin de erratas. Mejoras en la expresin del concepto de Closure. Adaptacin del contenido a la versin 1.2 de Grails. Nuevo captulo sobre soporte para Groovy y Grails en IDEs. Introduccin al desarrollo de servicios REST JSR 311 con grails-jaxrs. Referencia sobre el archivo BuildConfig.groovy

Pgina 236

Consigue la ltima versin de este manual en http://www.manual-de-grails.es v1.1.0 16 de Diciembre de 2009

Pgina 237

You might also like