3. Introducción a Grails. Scaffolding.

En esta primera sesión de Grails, comenzaremos, como no puede ser de otra forma, viendo una descripción de lo que es Grails, sus características y las ventajas que conlleva su uso como entorno para el desarrollo rápido de aplicaciones. Seguiremos analizando su arquitectura y las herramientas de código abierto que aúna Grails y terminaremos desarrollando nuestra primera aplicación en Grails aprovechándonos del scaffolding.

3.1. ¿Qué es?

Grails es un framework para el desarrollo de aplicaciones web basado en el lenguaje de programación Groovy, que a su vez se basa en la Plataforma Java. Grails está basado en los paradigmas convención sobre configuración y DRY (don’t repite yourself) o no te repitas, los cuales permiten al programador olvidarse en gran parte de los detalles de configuración de más bajo nivel.

Como la mayoría de los framework de desarrollo web, Grails está basado en el patrón Modelo Vista Controlador (MVC). En Grails los modelos se conocen como clases de dominio que permiten a la aplicación mostrar los datos utilizando la vista. A diferencia de otros frameworks, en Grails las clases de dominio de Grails son automáticamente persistidas y es incluso posible generar el esquema de la base de datos. Los controladores por su parte, permiten gestionar las peticiones a la aplicación y organizar los servicios proporcionados. Por último, la vista en Grails son las conocidas como Groovy Server Pages (GSP) (análogamente a las Java Server Pages -JSP-) y habitualmente se encargan de generar el contenido de nuestra aplicación en formato HTML.

Como comentábamos anteriormente, Grails permite al programador olvidarse de gran parte de la configuración típica que incluyen los frameworks MVC. Además Grails se aprovecha de un lenguaje dinámico como Groovy para acortar los tiempos de desarrollo y que el equipo de desarrolladores puedan centrarse simplemente en escribir código, actualizar, testear y depurar fallos. Esto hace que el desarrollo de la aplicación sea mucho más ágil que con otros frameworks MVC.

Habitualmente cuando hablamos de framework, se entiende como un marco de los programadores pueden utilizar las técnicas del Modelo Vista Controlador para el desarrollo rápido de sus aplicaciones. Pero, ¿qué pasa con el resto de elementos necesarios para el desarrollo de una aplicación como pueden ser los servidores web o los gestores de bases de datos?. En este sentido, Grails no es simplemente un framework de desarrollo de aplicaciones sino que es más una plataforma completa, puesto que incluye también un contenedor web, bases de datos, sistemas de empaquetado de la aplicación y un completo sistema para la realización de tests. De esta forma, no debemos perder el tiempo buscando y descargando un servidor web para nuestra futura aplicación o un gestor de base de datos. Ni tan siquiera será necesario escribir complicados scripts de configuración para el empaquetado de la aplicación. Todo esto se convierte en una tarea tan sencilla como instalar Grails.

3.1.1. ¿Qué empresas utilizan Grails?

Desde los inicios de Grails, muchas han sido las empresas que apostaron por este framework y que a día de hoy siguen utilizándolo para desarrollar sus aplicaciones.

3.2. Características de Grails

Algunas de las características más importantes que presenta Grails son las siguientes:

3.2.1. Convención sobre configuración

En lugar de tener que escribir interminables archivos de configuración en formato XML, Grails se basa en una serie de convenciones para que el desarrollo de la aplicación sea mucho más rápido y productivo. Además, gracias al uso de convenciones, se refuerza el otro principio del que hablábamos anteriormente, DRY (don’t repite yourself) o no te repitas.

3.2.2. Tests

Una de las partes más importantes en el desarrollo de software se refiere a los tests implementados que garantizan un software de calidad y el fácil mantenimiento de una aplicación. Gracias a estos tests, es muy sencillo detectar y solucionar fallos provocados por cambios en el código. Cada vez que se genera en Grails una clase de dominio o un controlador, paralelamente es generado también un test para comprobar la nueva clase o controlador, que por supuesto nosotros deberemos completar (Grails es muy bueno, pero no lo hace todo).

Grails distingue entre tests unitarios y tests de integración. Los tests unitarios son tests sin dependencias de ningún tipo, salvo algún que otro objeto mock. Por otro lado, los tests de integración tienen acceso completo al entorno de Grails, incluyendo la base de datos. Además, Grails permite también la creación de tests funcionales para comprobar la funcionalidad de nuestra aplicación web a nivel de interacción con el usuario.

3.2.3. Scaffolding

El scaffolding es una característica de determinados frameworks que permite la generación automática de código para las cuatro operaciones básicas de cualquier aplicación, que son la creación, lectura, edición y borrado, lo que en inglés se conoce como CRUD (create, read, update and delete).

Grails permite también utilizar scaffolding en nuestras aplicaciones a través de un plugin que viene instalado por defecto. En versiones anteriores, el scaffolding venía como parte del core de Grails, sin embargo en las últimas versiones esta característica ha sido movida a un plugin. El scaffolding en Grails se consigue escribiendo muy pocas líneas de código, con lo que podemos centrarnos en especificar las propiedades, comportamientos y restricciones de nuestras clases de dominio.

Una gran cantidad de aplicaciones consisten en simplemente ofrecer la posibilidad a los usuarios de realizar esas cuatro operaciones básicas que comentábamos anteriormente sobre algunas entidades o clases de dominio con lo que en ocasiones este scaffolding nos ahorrará mucho tiempo.

3.2.4. Mapeo objeto-relacional

Grails incluye un potente framework para el mapeo objeto-relacional conocido como GORM (Grails Object Relational Mapping). Como cualquier framework de persistencia, GORM permite mapear objetos contra bases de datos relacionales y representar relaciones entre dichos objetos del tipo uno-a-uno, uno-a-muchos y muchos-a-muchos.

Por defecto, Grails utiliza Hibernate por debajo para realizar este mapeo, con lo que no debemos preocuparnos de que tipo de base de datos vamos a utilizar en nuestra aplicación (MySQL, Oracle, SQL Server, etc) porque Grails se encargará por nosotros de esta parte. Además, en los últimos tiempo están proliferando lo que se conoce como las bases de datos noSQL como MongoDB, Redis, Neo4j, etc. Aunque éstos tipos de bases de datos todavía no están soportadas en el núcleo de Grails, si están apareciendo al mismo tiempo diversos plugins para la utilización de éstas sin apenas modificar nada en nuestra aplicación.

3.2.5. Plugins

Sin embargo, Grails no siempre es la solución a cualquier problema que se nos pueda plantear en el desarrollo de aplicaciones web. Para ayudarnos, Grails dispone de una arquitectura de plugins con una comunidad de usuarios detrás (cada vez más grande) que ofrecen plugins para seguridad, AJAX, testeo, búsqueda, informes, servicios web, etc. Este sistema de plugins hace que añadir complejas funcionalidades a nuestra aplicación se convierte en algo muy sencillo. En la actualidad hay alrededor de 1200 plugins desarrollados para Grails.

3.2.6. Internacionalización (i18n)

Cuando creamos un proyecto en Grails, automáticamente se crea toda la estructura de datos necesaria para la internacionalización de la aplicación sin ningún problema.

3.2.7. Software de código abierto

Por suerte, Grails no sufre del síndrome Not Invented Here (NIH) y lo hace integrando en su arquitectura las mejores soluciones de software libre del mercado para crear un framework robusto. Veamos cuales son estas soluciones.

Groovy

Groovy es la parte fundamental en la que se basa Grails. Como vimos en las dos primeras sesiones, Groovy es un potente y flexible lenguaje de programación. Su integración con Java, las características como lenguaje dinámico y su sintaxis sencilla, hacen de este lenguaje de programación el compañero perfecto para Grails.

Framework Spring

El framework Spring ofrece un alto nivel de abstracción al programador que en lugar de tratar directamente con las transacciones, proporciona una forma para declarar dichas transacciones utilizando los POJOs (Plain Old Java Objects), con lo que el programador se puede centrar en la implementación de la lógica de negocio.

Hibernate

Hibernate es un framework de persistencia objeto-relacional y constituye la base de GORM. Es capaz de mapear complejas clases de dominio contra las tablas de una base de datos, así como establecer las relaciones entre las distintas tablas.

SiteMesh

SiteMesh es un framework web para el renderizado de documentos HTML que implementa el patrón de diseño Decorator con componentes como cabeceras, pies de páginas y sistemas de navegación.

Tomcat y Jetty

Como comentábamos anteriormente, Grails es una plataforma completa, y esto es en parte gracias a la inclusión de un servidor web como Jetty o Tomcat. Esto no significa que Grails solo funcione con estos dos servidores de aplicaciones sino que en nuestra instalación local de Grails podremos utilizar cualquiera de ellos.

H2

Grails también incluye un gestor de bases de datos relacionales como H2. H2 es un gestor de base de datos en memoría de tamaño muy reducido y que en la mayoría de los casos nos servirá para nuestra fase de desarrollo (nunca para producción). Esto tampoco quiere decir que nuestras aplicaciones desarrolladas en Grails sólo funcionen con H2, sino que para desarrollar nuestra aplicación no vamos a necesitar ningún gestor de base de datos externo.

Spock

En las primeras versiones de Grails, se utilizaba como framework para el desarrollo de tests el ampliamente aceptado JUnit, pero en las últimas versiones se ha decidido utilizar otro framework que ha tenido gran aceptación por parte de la comunidad llamado Spock. Spock nos permitirá realizar tests unitarios, de integración y funcionales, tal y como veremos en la sesión 6.

Gant

Gant es un entorno en línea de comandos que envuelve el archiconocido sistema de automatización de tareas Apache Ant. Con Gant vamos a poder realizar todo tipo de tareas en un proyecto Grails, como la creación de todo tipo de artefactos en la aplicación, la generación del código de scaffolding necesario, la realización de las pruebas unitarias y de integración y el empaqueta de la aplicación, entre otras cosas.

3.3. Arquitectura

Ahora que ya tenemos una idea de lo que es Grails y las ventajas que nos puede aportar a la hora de desarrollar nuestros proyectos web, veamos gráficamente su arquitectura.

Arquitectura Grails

Podemos decir que la arquitectura de Grails está formada por cuatro capas claramente diferenciadas. La base de la arquitectura de Grails es la máquina virtual de Java. Por encima de ésta se encuentran los lenguajes de programación en lo que está basado Grails, Java y Groovy. En la tercera capa tenemos el propio framework Grails, al cual le acompañan todos los frameworks de los que hablábamos en la sección anterior, SiteMesh, Spring, GORM, etc. En esta capa también se ha añadido una opción abierta como es la posibilidad de incluir otras librerías externas que no están incluidas en Grails. La última capa está formada por la aplicación en si, siguiendo el patrón modelo vista controlador.

Además, envolviendo a todo el proyecto Grails aparece Gant, la herramienta en línea de comandos que nos permitirá una gran variedad de acciones sobre el mismo.

Desde el punto de vista de la ejecución de un proyecto Grails, se podría esquematizar de la siguiente forma:

Grails runtime

De la imagen podemos concluir que una página web realiza una petición al servidor web. Esta petición se pasa a un controlador, el cual podrá utilizar o no una clase de dominio (modelo). Esta clase de dominio puede ser a su vez estar persistida en una base de datos gracias a GORM. Una vez el controlador termina, pasa la petición al correspondiente GSP para que renderice la vista y sea enviada de nuevo al navegador en forma de página HTML.

3.4. Instalación de Grails

Si tenemos en cuenta lo que decíamos anteriormente de que Grails es un completo framework con un servidor web, un gestor de base de datos y el resto de características ya comentadas, podríamos pensar que su instalación puede ser muy complicada. Sin embargo, la instalación de Grails se convierte en un juego de niños, ya que nos olvidamos de tener que buscar soluciones externas para cada uno de los aspectos relacionados con el desarrollo de una aplicación web.

Aquí vamos a configurar Grails para poder utilizarlo tanto desde línea de comandos como desde el entorno de desarrollo IntelliJ IDEA.

3.4.1. Instalación de Grails en línea de comandos

Tal y como hacíamos en la instalación de Groovy, vamos a utilizar el gestor de paquetes sdkman (http://sdkman.io/). Estos son los pasos para instalar Grails en nuestro ordenador:

curl -s get.sdkman.io | bash

source "$HOME/.sdkman/bin/sdkman-init.sh"

sdk list grails

sdk install grails 2.5.2

Si necesitaramos alternar entre varias versiones de Grails, simplemente deberías ejecutar:

sdk use grails 2.1.0

3.4.2. Instalación en IntelliJ IDEA

En principio IntelliJ IDEA ofrece automáticamente la posibilidad de crear proyectos Grails gracias al plugin instalado por defecto. Puedes comprobarlo en las preferencias de IntelliJ IDEA > IDE Settings > Plugins y ahí buscar el plugin de Grails. Cuando intentemos crear un nuevo proyecto en Grails, IntelliJ nos pedirá que le indiquemos donde se encuentra el framework instalado.

Crear proyecto Grails
Seleccionar la versión de Grails desde la instalación de sdk

3.5. Scaffolding

Una vez ya tenemos configurado nuestro entorno de desarrollo, pasemos a la acción desarrollando con Grails una sencilla aplicación. En este módulo, vamos a desarrollar un ejemplo de lo que sería el completo desarrollo de una aplicación web que nos permita manejar una lista de tareas. Empezaremos desarrollando este ejemplo de aplicación para explicar como Grails implementa el scaffolding. Pero, ¿qué es el scaffolding?

El scaffolding es un término utilizado en programación para designar la construcción automática de aplicaciones a partir del esquema de la base de datos. Está soportado por varios frameworks MVC y Grails no podía ser menos y el equipo de desarrollo decidió incluirlo entre sus características más importantes. La idea del scaffolding es, partiendo del esquema de la base de datos, generar el código necesario para implementar las cuatro operaciones básicas en cualquier aplicación, que son: creación, lectura, actualización y borrado. Este tipo de aplicaciones se las conoce como CRUD (create, read, update y delete).

Grails además nos ofrece dos tipos de scaffolding, el dinámico, en el cual Grails genera por nosotros al vuelo el código referente a las vistas y a los controladores y por otro lado el scaffolding estático en el que Grails generará de forma estática el código de controladores y vistas.

Como comentabamos anteriormente, vamos a ver un ejemplo de lo que es el scaffolding, desarrollando la típica aplicación todo, aplicación que iremos mejorando durante todo este módulo.

3.5.1. Descripción de la aplicación ejemplo

Básicamente el funcionamiento de la aplicación debe permitir la creación y mantenimiento de tareas así como la posibilidad de categorizarlas. Para simplificar la aplicación, una tarea sólo podrá pertenecer como mucho a una categoría mientras que una categoría podrá tener por supuesto muchas tareas.

Además, también vamos a permitir la posibilidad etiquetar dichas tareas, con lo que una tarea puede tener varias etiquetas y una etiqueta estar asignada a varias tareas.

Por el momento, no nos vamos a preocupar de la gestión de usuarios, ya que lo haremos en la sesión 7 utilizando un plugin que se encargará por nosotros de todo el tema de seguridad de nuestra aplicación.

3.5.2. Creación del proyecto Grails

Si todo ha ido bien en la instalación de Grails, podremos crear nuestra primera aplicación en Grails gracias al comando grails. Este será el comando que utilizaremos a lo largo de todo el curso para crear todas las partes de nuestra aplicación. Para ver un listado completo de las opciones del comando grails, podemos ejecutar grails help. Si echamos un primer vistazo a esta listado, descubriremos la opción create-app, la cual nos servirá para crear la estructura de directorios de la aplicación. Ejecutamos grails create-app todo y se nos generará el directorio todo con una serie de subdirectorios que comentaremos en breve.

Esta estructura de directorios generada automáticamente por Grails viene como consecuencia de lo que comentábamos anteriormente como uno de los paradigmas en que se basa Grails, convención sobre configuración. De esta forma, Grails nos genera la estructura de directorios que albergará todo nuestro proyecto para que nosotros lo vayamos completando. Veamos para que sirven los directorios más importantes generados dentro de nuestro proyecto todo.

Directorio Descripción

grails-app/conf

Ficheros de configuración de la aplicación

grails-app/conf/hibernate

Archivos de mapeado de Hibernate

grails-app/conf/spring

Archivos de mapeado de Spring

grails-app/controllers

Controladores de la aplicación que gestionan las peticiones

grails-app/domain

Clases de dominio del modelo

grails-app/i18n

Mensajes para la internacionalización de la aplicación

grails-app/services

Servicios

grails-app/taglib

Librerías de etiquetas dinámicas

grails-app/utils

Utilidades específicas de Grails

grails-app/views

Archivos GSP

grails-app/views/layout

Archivos de diseño de las páginas web

grails-app/assets/images

Imágenes utilizadas por la aplicación en el entorno del plugin pipeline

grails-app/assets/javascripts

Archivos javascript utilizados por la aplicación en el entorno del plugin pipeline

grails-app/assets/stylesheets

Hojas de estilo utilizadas por la aplicación en el entorno del plugin pipeline

lib

Archivos JAR de terceras partes, tales como controladores de bases de datos

scripts

Scripts GANT para el automatizado de tareas

src/java

Archivos fuente adicionales en Java

src/groovy

Archivos fuente adicionales en Groovy

test/integration

Tests de integración

test/unit

Tests unitarios

web-app

Artefactos web que finalmente serán comprimidos a un WAR (Web Application Archive)

web-app/css

Hojas de estilo

web-app/images

Imágenes de la aplicación

web-app/js

Javascript

web-app/WEB-INF

Archivos de configuración para Spring o SiteMesh

Ahora que ya tenemos una primera idea de lo que significa cada uno de los directorios generados por Grails al crear un proyecto, vamos a abrirlo con el editor IntelliJ IDEA. Grails es capaz de crear también los archivos de configuración necesarios para que podamos editar el proyecto con diferentes editores como Eclipse, Textmate y NetBeans, con lo que simplemente abrimos el editor y localizamos el proyecto todo y lo abrimos como un nuevo proyecto. Como vemos en la imagen, IDEA ha cambiado la estructura de directorios por una más clara para el desarrollador, aunque siempre podemos ver la estructura real de directorios si accedemos a la vista Project.

Aplicación Grails con IntelliJ Idea

Nuestro proyecto ya está listo para ser ejecutado, aunque imaginarás que por el momento no hará nada. Para ver la primera versión del proyecto todo podemos ejecutar el comando grails run-app, que nos generará una aplicación en la dirección http://localhost:8080/todo. El comando grails run-app lo que ha hecho es crear una instancia del servidor web Tomcat en el puerto 8080 y cargar en él la aplicación todo. Por ahora esta aplicación hace más bien poco y simplemente nos muestra un mensaje de bienvenida, pero vamos a ver lo sencillo que es generar su contenido.

3.5.3. Creación de clases de dominio

Al desarrollar una aplicación de este tipo, lo habitual es crear en primer lugar las clases de dominio necesarias para después pasar a generar los controladores, así que vamos a empezar creando la clase de dominio referente a los todos. En Grails tenemos el comando grails create-domain-class para generar una determinada clase de dominio, con lo que si ejecutamos grails create-domain-class es.ua.expertojava.todo.todo, Grails nos creará la estructura necesaria para las tareas de nuestra aplicación. En caso de no indicar el nombre de la clase, el sistema nos preguntará por él.

Como podemos comprobar en nuestro proyecto con IDEA, se nos ha creado una clase de dominio llamada Todo, que como ves empieza por mayúscula a pesar de que nosotros introdujimos el nombre de la clase de dominio en minúsculas. Esto es debido a que Grails sigue una serie de convenios para el nombre de las clases. El contenido de Todo.groovy es el siguiente:

package es.ua.expertojava.todo

class Todo {

    static constraints = {
    }
}

Además, también se crea un test unitario llamado es.ua.expertojava.todo.TodoSpec, que de momento dejaremos tal cual está pero que volveremos a él en la sesión 6 en la que hablaremos de los tests unitarios.

package es.ua.expertojava.todo

import grails.test.mixin.TestFor
import spock.lang.Specification

/**
 * See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
 */
@TestFor(Todo)
class TodoSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    void "test something"() {
    }
}

La clase de dominio Todo está preparada para que le añadamos los campos necesarios, tales como título, descripción, fecha, etc. La información referente a las tareas serán título, descripción, fecha, fechaRecordatorio y url. Con estos datos, la clase de dominio Todo quedaría así:

package es.ua.expertojava.todo

class Todo {
    String title
    String description
    Date date
    Date reminderDate
    String url

    static constraints = {
        title(blank:false)
        description(blank:true, nullable:true, maxSize:1000)
        date(nullable:false)
        reminderDate(nullable:true)
        url(nullable:true, url:true)
    }

    String toString(){
        title
    }
}

Como puedes comprobar, en ningún momento se ha indicado ninguna propiedad como clave primaria y esto es debido a que Grails añade siempre las propiedades id y version, los cuales sirven respectivamente como clave primaria de la tabla en cuestión y para garantizar la integridad de los datos. La propiedad version es un mecanismo utilizado en Hibernate para el bloqueo de las tablas y que evita que se produzcan inconsistencias en los datos.

Por otro lado, la clase Todo no sólo contiene propiedades sino que también se han añadido una serie de restricciones (constraints) que deben cumplir dichas propiedades para que una tarea se pueda insertar en la base de datos. Por ejemplo, la propiedad title no puede dejarse en blanco, la propiedad date no puede ser null, mientras que las propiedades description, reminderDate y url pueden tener un valor null y además ésta última, en caso de contener valor, debe ser una dirección url bien formada. Además, observa también como la descripción no puede exceder de 1000 caracteres.

3.5.4. Creación de controladores

Ahora que tenemos nuestra primera clase de dominio creada, necesitamos un controlador que gestione todas las peticiones que le lleguen a esta clase de dominio. El controlador es el encargado de gestionar la interacción entre la vista y las clases de dominio, con lo que podemos decir sin género de dudas que es la parte más ardua del sistema. Sin embargo, gracias a que Grails nos permite utilizar scaffolding esto se convierte de nuevo en un juego para niños.

Para crear un controlador en Grails, debemos ejecutar el comando grails create-controller y se generará un nuevo controlador en el directorio grails-app/controllers, así como un test unitario en el directorio test/unit/<paquete>. Antes de seguir vamos a crear el controlador de la clase Todo ejecutando grails create-controller es.ua.expertojava.todo.todo, el cual creará el archivo grails-app/controllers/es/ua/expertojava/todo/TodoController.groovy con el siguiente contenido

package es.ua.expertojava.todo

class TodoController {

    def index() { }
}

Además, tal y como pasaba cuando creábamos la clase de dominio, Grails crea por nosotros un test unitario llamado es.ua.expertojava.todo.TodoControllerSpec que nos permitirá más adelante testear el controlador.

Para poder utilizar scaffolding de la clase Todo simplemente debemos cambiar la línea

def index = {}

por el siguiente código

def scaffold = Todo

o bien por

def scaffold = true

Si actualizamos la web de la aplicación veremos como nos aparece un nuevo enlace en el que podremos controlar las tareas de nuestra aplicación. El scaffolding de Grails ha creado por nosotros los cuatro métodos necesarios para la gestión de las tareas creación, lectura, edición y borrado. En la siguiente imagen podemos ver el formulario para añadir una nueva tarea.

Añadir una tarea

Si nos fijamos bien, observaremos que el orden para el formulario de creación de una nueva tarea sigue el mismo orden en el que aparecen definidas las restricciones para la validación de los datos. También es interesante ver como para la propiedad description ha creado un textarea en lugar de un campo text como ha hecho con el resto de propiedades de tipo String. Esto es porque para el campo description hemos establecido la restricción del tamaño máximo.

Probemos ahora a insertar tareas que no cumplan alguna de las restricciones que le impusimos en la definición de la clase de dominio. Si por ejemplo intentamos insertar una nueva tarea sin especificar su título el sistema nos proporcionará un error indicando que el campo en cuestión no puede estar vacío. Además, el campo de texto aparece remarcado en rojo para que el usuario sepa que ahí está pasando algo no permitido.

Si solucionamos este problema con el título, se insertará una nueva tarea en la base de datos de nuestra aplicación, que posteriormente podremos visualizar, editar y eliminar.

Continúemos con nuestro pequeño ejemplo de scaffolding, y para ello vamos a definir también la clase de dominio y el controlador para las categorías de las tareas. Empecemos creando las clases de dominio necesarias y empecemos por las categorías de las tareas. Para ello ejecutamos el comando grails create-domain-class es.ua.expertojava.todo.category. De estas categorías necesitamos conocer su nombre y una descripción.

package es.ua.expertojava.todo

class Category {

    String name
    String description

    static hasMany = [todos:Todo]

    static constraints = {
        name(blank:false)
        description(blank:true, nullable:true, maxSize:1000)
    }

    String toString(){
        name
    }
}

Lo novedoso en la declaración de la clase Category es la aparición de la especificación de la relación entre ésta y la clase Todo. Si pensamos en la relación existente entre las tareas y las categorías, está claro que esta relación es del tipo uno a muchos, es decir, que una categoría puede tener muchas tareas y que una tarea sólo pertenecerá por simplicidad a una categoría. Teniendo esto en cuenta, debemos especificar en la clase de dominio Todo la otra parte de la relación. Esto lo vamos a hacer añadiendo una nueva propiedad estática en la case de dominio del siguiente modo:

package es.ua.expertojava.todo

class Todo {
    String title
    String description
    Date date
    Date reminderDate
    String url
    Category category

    static constraints = {
        title(blank:false)
        description(blank:true, nullable:true, maxSize:1000)
        date(nullable:false)
        reminderDate(nullable:true)
        url(nullable:true, url:true)
        category(nullable:true)
    }

    String toString(){
        "title"
    }
}

Una vez ya tenemos definidas la clase de dominio Category, podemos crear el controlador e indicarle que queremos utilizar el scaffolding para gestionar su información. Para ello ejecutamos grails create-controller es.ua.expertojava.todo.category.

package es.ua.expertojava.todo

class CategoryController {

    def scaffold = Category
}

Por último, vamos a añadir la clase de dominio referente a las etiquetas que vamos a poder asignar a las tareas. Ejecutamos grails create-domain-class es.ua.expertojava.todo.tag:

package es.ua.expertojava.todo

class Tag {

    String name

    static hasMany = [todos:Todo]

    static constraints = {
        name(blank:false, nullable:true, unique:true)
    }

    String toString(){
    	name
    }
}

Como puedes observar, una etiqueta puede estar asignada a muchas tareas. De igual forma, una tarea podrá tener muchas etiquetas. Más adelante veremos a fondo como se deben establecer este tipo de relaciones.

package es.ua.expertojava.todo

class Todo {
    String title
    String description
    Date date
    Date reminderDate
    String url
    Category category

    static hasMany = [tags:Tag]
    static belongsTo = [Tag]

    static constraints = {
        title(blank:false)
        description(blank:true, nullable:true, maxSize:1000)
        date(nullable:false)
        reminderDate(nullable:true)
        url(nullable:true, url:true)
        category(nullable:true)
    }

    String toString(){
        "title"
    }
}

Como siempre, no olvidemos crear el controlador que se encargará de gestionar las etiquetas:

package es.ua.expertojava.todo

class TagController {

    def scaffold = Tag
}

Ahora sí, nuestra aplicación empieza a tomar forma de como debe ser la aplicación final, aunque por supuesto todavía quedan muchas cosas que iremos viendo a lo largo del módulo. Ahora mismo, podemos empezar a probar la aplicación insertando datos en cada una de las clases y comprobar que todo funciona correctamente. Sin embargo, la labor de introducción de los datos a mano en la aplicación es algo muy repetitivo y aburrido, así que vamos a ver como podemos convertir esta tarea en algo más sencillo y no tener que repetirla cada vez que probamos la aplicación (recuerda que ahora mismo la base de datos está en memoria con lo que se destruye cada vez que reiniciamos la aplicación).

En el directorio de configuración de nuestra aplicación (grails-app/conf) tenemos un archivo llamado BootStrap.groovy cuya funcionalidad es posibilitar la realización de acciones al arrancar y al finalizar nuestra aplicación. Como ya estaréis imaginando, vamos a aprovechar este fichero para introducir algunos datos en nuestra aplicación para tener algo de información ya introducida en nuestra aplicación. El siguiente ejemplo, inserta tareas, categorías y etiquetas en nuestra aplicación.

import es.ua.expertojava.todo.*

class BootStrap {

    def init = { servletContext ->
        def categoryHome = new Category(name:"Hogar").save()
        def categoryJob = new Category(name:"Trabajo").save()

        def tagEasy = new Tag(name:"Fácil").save()
        def tagDifficult = new Tag(name:"Difícil").save()
        def tagArt = new Tag(name:"Arte").save()
        def tagRoutine = new Tag(name:"Rutina").save()
        def tagKitchen = new Tag(name:"Cocina").save()

        def todoPaintKitchen = new Todo(title:"Pintar cocina", date:new Date()+1)
        def todoCollectPost = new Todo(title:"Recoger correo postal", date:new Date()+2)
        def todoBakeCake = new Todo(title:"Cocinar pastel", date:new Date()+4)
        def todoWriteUnitTests = new Todo(title:"Escribir tests unitarios", date:new Date())

        todoPaintKitchen.addToTags(tagDifficult)
        todoPaintKitchen.addToTags(tagArt)
        todoPaintKitchen.addToTags(tagKitchen)
        todoPaintKitchen.category = categoryHome
        todoPaintKitchen.save()

        todoCollectPost.addToTags(tagRoutine)
        todoCollectPost.category = categoryJob
        todoCollectPost.save()

        todoBakeCake.addToTags(tagEasy)
        todoBakeCake.addToTags(tagKitchen)
        todoBakeCake.category = categoryHome
        todoBakeCake.save()

        todoWriteUnitTests.addToTags(tagEasy)
        todoWriteUnitTests.category = categoryJob
        todoWriteUnitTests.save()
    }
    def destroy = { }
}

3.5.5. Scaffolding estático

Una vez hemos visto lo rápido que hemos desarrollado la base de nuestra aplicación, vamos a ver como podemos llegar algo más lejos con nuestras aplicaciones gracias al scaffolding estático. Hasta el momento, el código de nuestros controladores y vistas se genera al vuelo y no podemos realizar ni siquiera una pequeña modificación a estos artefactos.

Para pasar de scaffolding dinámico a estático, Grails dispone de tres comandos para realizar esta tarea:

  • generate-controller

  • generate-views

  • generate-all

Los tres comandos esperan como parámetro una clase de dominio para la cual generar el código necesario. Veamos un ejemplo sobre las clases de dominio de la aplicación.

grails generate-all es.ua.expertojava.todo.Todo

Tras ejecutar este comando, si echamos un vistazo a nuestro proyecto en IntelliJ IDEA, veremos como el controlador es.ua.expertojava.todo.TodoController y el directorio de las vistas views/todo han cambiado considerablemente.

Por un lado, el controlador ahora tiene todo el contenido necesario de forma estática de forma que vamos a poder modificarlo según nuestras necesidades. Además, en el directorio de las vistas correspondientes a la clase de dominio todo podemos ver los archivos necesarios para poder completar el CRUD de la clase Todo.

Proyecto tras generar todo

Los otros dos comandos comentados anteriormente van a realizar en conjunto las mismas acciones que el comando generate-all. Veamos un ejemplo con la clase de dominio Tag.

grails generate-controller es.ua.expertojava.todo.Tag
grails generate-views es.ua.expertojava.todo.Tag

Como podrás comprobar en el proyecto, el controlador es.ua.expertojava.todo.TagController se ha definido de forma estática y las vistas han sido generadas para poder ser modificadas más fácilmente.

3.6. Ejercicios

3.6.1. Marcar como realizada una tarea (0.25 puntos)

En la definición de la aplicación todo hemos pasado por alto algo fundamental y es que una tarea puede haber sido realizada o no. Añade la información necesaria a nuestras clases de dominio para saber si una tarea ha sido ya completada.

No olvides añadir el valor deseado en el archivo Bootstrap.groovy para la nueva propiedad añadida.

3.6.2. Modificación pantalla inicial (0.25 puntos)

Vamos a modificar la pantalla de bienvenida a la aplicación con las siguientes indicaciones:

  • Eliminar el logo de Grails de la parte superior para indicar el nombre la aplicación

  • Indicar nuestro nombre, apellidos y DNI

  • Añadir una imagen de vuestro perfil (puede valer la misma que tenéis en el campus virtual)

  • Eliminar el bloque de la izquierda donde aparece toda la información relativa a nuestra aplicación

  • Añadir una descripción apropiada de la aplicación

  • Añadir los enlaces correspondientes a las acciones que podemos realizar por el momento en nuestra aplicación

Podría quedar algo así:

Ejemplo pantalla inicial aplicación TODO

3.6.3. Scaffolding estático sobre la clase Categoría (0.75 puntos)

La única clase de dominio que nos queda por definir de forma estática es la referente a las categorías. Utilicemos también scaffolding estático para esta clase. Además, vamos a realizar las siguientes modificaciones sobre las vistas de las categorías:

  • Cuando creamos una categoría, Grails nos ofrece un enlace para crear tareas que por el momento vamos a eliminar.

Crear una categoría
  • En el listado de categorías, vamos a eliminar el campo descripción porque en ocasiones esa descripción puede ser demasiado extensa.

  • Cuando creamos una categoría utilizando la aplicación, el mensaje que aparece indica que la categoría con identificado X ha sido creada correctamente. Realiza los cambios necesarios en el controlador para que en lugar de indicar el identificador, aparezca el nombre de la nueva categoría creada.

Indicando el identificador de la categoría
Indicando el nombre de la categoría