Publica tu how-to

Dinos como hacer lo que sabes hacer, mándanos un email a wdonet@gmail.com y lo publicamos (dos días máximo) o si te interesa unirte al equipo de redactores, también háznoslo saber por correo.

Creacion de un proyecto base con Grails 2.0.3

Vamos a crear un proyecto web base para una aplicación que podría usar un kinder considerando solo poder hacer Altas Bajas y Cambios (ABC) de dos entidades Tutores y Alumnos.  Yo trabajaré en un Linux Mint, las instrucciones en consola son similares en cualquier distribución derivada de Debian o Ubuntu, para windows solo cambiarían las carpetas y las variables de entorno.

Empecemos instalando Grails.

Necesitamos tener instalado java y haber definido nuestra variable de entorno JAVA_HOME.
  1. Descargar grails
  2. Descomprimir ZIP en una carpeta (la mia será /opt )
  3. Crear las variables de entorno GRAILS_HOME y JAVA_HOME (si no existe)
export GRAILS_HOME=/opt/grails-2.0.3
export PATH=$PATH:/opt/grails-2.0.3/bin


Para comprobar que nuestra instalación está completa debemos ejecutar el comando grails para obtener la versión.  En algunos sistemas como el mío se requiere reiniciar la sesión de usuario para que se apliquen los cambios en las variables de entorno.

$ grails -version
Grails version: 2.0.3


Ahora creamos nuestra aplicación, se genera una carpeta con el nombre de la aplicación, ingresamos a dicha carpeta y luego abrimos la consola de grails.

$ grails create-app kinder
| Created Grails Application at /home/wdonet/branches/grails/kinder
$ cd kinder/
$ ls
application.properties  grails-app  lib  scripts  src  test  web-app
$ grails
| Downloading: plugins-list.xml
grails> help

Podemos usar el comando help para ver todos los comandos que tenemos disponibles en la consola de grails, incluso puedes obtener ayuda de un comando en especifico escribiendo por ejemplo : help create-appPero toma nota que la consola de grails es una forma para jugar con el ambiente de tu proyecto, si quieres ejecutar tu aplicación es mejor usar el comando grails (fuera de la consola).



Como yo utilizo IntelliJIDEA como IDE para desarrollo, le voy a agregar el soporte para este IDE al proyecto, pero no es necesario, si usas eclipse, STS u otro, este paso no es necesario ya que Grails genera por defecto el archivo de configuración para abrir el proyecto en eclipse.

grails> integrate-with --intellij
| Created IntelliJ project files..




Convención sobre la configuración

Algo que debemos entender antes de continuar, por si no lo sabías, es el concepto de "Convention over configuration".  Grails usa esta convención para configurarse a sí mismo, en otras palabras, cada nombre y ubicación de los archivos es usado como parte de la configuración de la aplicación en lugar de explicitamente declararlo en algun lado.  Por tanto, es necesario que te familiarises con la estructura de directorios que se generó en el proyecto que acabamos de crear.

Los elementos dentro de la carpeta kinder son:

Configurar la Base de Datos

Como todo sistema, necesitamos de un lugar donde almacenar nuestros datos y en este caso usaremos MySQL con el driver 5.1.18.
  1. Debes editar el archivo kinder/grails-app/conf/BuildConfig.groovy.
    1. (optativo) Descomentar, en repositorios, la linea mavenLocal() si ya tienes instalado maven en tu equipo, Grails se beneficia del repositorio local en tu máquina, sino usa por defecto los repositorios centrales de Grails y Maven.
    2. Descomentar, dentro de las dependencias, la linea runtime 'mysql:mysql-connector-java:X.X.X' y sustituir la versión actual por la 5.1.18.
  2. Debes editar el archivo kinder/grails-app/conf/DataSource.groovy.
    1.  Agregar los datos de conexión a tu base de datos
dataSource {
    dbCreate = "update"
    driverClassName = "com.mysql.jdbc.Driver"
    username = "root"
    password = "admin"
}
environments {
    development {
        dataSource {
            url = "jdbc:mysql://localhost/kinder"
        }
    }
    test {
        dataSource {
            url = "jdbc:mysql://pruebas/kinder"
        }
    }
    production {
        dataSource {
            url = "jdbc:mysql://produccion/kinder"
            username = "usuario_produccion"
            password = "pass_produccion"
        }
    }
}

Como solamente usaremos el ambiente desarrollo (el default), basta con dejar toda la configuración en datasource o development.  Pero el ejemplo muestra que el datasource externo define las propiedades comunes y los datasource internos de development, test y production sobreescriben la configuración externa, por ejemplo la url del ambiente donde se va a conectar.

La propiedad dbCreate puede tener cualquiera de los siguientes valores:
  1. create, elimina el esquema actual y luego lo crea cuando levanta la aplicación.
  2. create-drop, igual que la anterior solo que elimina el esquema al terminar la aplicación.
  3. update, crea nuevas tablas, agrega indices o columnas que falten, no borra tablas, columnas, ni datos.  Pero toma en cuenta que no soportara muchos cambios y ahí convendria un create primero.
  4. validate, no crea nada ni borra nada, pero valida la similitud de tu configuración con lo que ya existe en la BD.  Si hay diferencias envía warnings!.
  5. cualquier otro valor, no hace nada.

A programar !

La parte central de la mayoría de proyectos Grails es su modelo de dominio el cual representa la capa de persistencia de los datos y esto es tan sencillo como crear clases de dominio que mapean las tablas en una Base de Datos.

Por esa razón vamos a crear las clases de dominio principales: Alumno, Tutor y un par de catalogos: Grupo, Estado, Municipio y Postal.  Las instrucciones se vuelven repetitivas para cada clase así que es probable que no las coloque en todas las secciones pero sin duda debes considerarlas.

Diagrama de Clases y sus relaciones entre sí. Da clic para ver en grande


$ grails create-domain-class mx.com.kinder.Alumno
| Created file grails-app/domain/mx/com/kinder/Alumno.groovy
| Created file test/unit/
mx/com/kinder/AlumnoTests.groovy
$ grails create-domain-class Tutor
| Created file grails-app/domain/
mx/com/kinder/Tutor.groovy
| Created file test/unit/
mx/com/kinder/TutorTests.groovy
Hacer lo mismo para el resto de clases y luego agregar sus propiedades a mano.

Agrega a la clase Tutor:
package mx.com.kinder

import mx.com.kinder.dto.Nombre
import mx.com.kinder.dto.Direccion

class Tutor {
    Nombre nombre
    Estado estado
    Municipio municipio
    Postal postal
    Direccion direccion
    Date fechaNacimiento
    String mail
    String telefonoCasa
    String telefonoOficina
    String telefonoCelular

    //para embeber los tres campos de nombres, paterno y materno en un DTO
    // o todos los campos de la direccion en un solo DTO
    static embedded = ['nombre', 'direccion']

    //el orden de los campos en constraints define el orden de los
    // elementos en la vista que se generara después.
    static constraints = {
        nombre()
        direccion(nullable: false)
        estado(nullable: false)
        municipio(nullable: false)
        postal(nullable: false)
        fechaNacimiento nullable: false
        mail email: true, blank: false, nullable: true
        telefonoCasa()
        telefonoOficina()
        telefonoCelular()
    }

}

Observa que los atributos de la clase en realidad son propiedades dado que Grails le inyecta automáticamente sus métodos getters y setters correspondientes, además se determina el nombre de la Tabla como el nombre de la clase y el nombre de las columnas como el nombre de cada propiedad.  La creación de estos elementos en la Base de Datos se hace de manera automática cuando se levante la aplicación.

Los constraints son validaciones que se ejecutan antes de la persistencia de los datos, para el caso de Tutor por ejemplo, ningún elemento de la dirección puede ser nulo; el mail si puede ser nulo pero no debe tener solo espacios, además se valida que la estructura del mail sea la de un correo con "email: true".

Agrega a la clase Alumno:
package mx.com.kinder

import mx.com.kinder.dto.Nombre
import mx.com.kinder.dto.Direccion

class Alumno {

    Nombre nombre
    Date fechaNacimiento
    Grupo grupo
    Tutor papa
    Tutor mama
    Direccion direccion

    static embedded = ['nombre', 'direccion']

    static constraints = {
        nombre()
        grupo()
        fechaNacimiento()
        papa()
        mama()
        direccion()
    }
}  


Debemos crear ahora los controladores (capa de clases que sirven de interfaz entre la vista web y la capa de persistencia - base de datos).  Grails puede generar los metodos del controller de forma automática a manera que queden programadas como servicios REST que se pueden exponer via web.  Toma en cuenta que el controlador se genera con base en las propiedades de la entidad.

$ grails create-controller mx.com.kinder.Alumno
$ grails create-controller mx.com.kinder.Tutor
$ grails create-controller mx.com.kinder.Estado 
$ grails create-controller mx.com.kinder.Municipio
$ grails create-controller mx.com.kinder.Postal

, o bien, usar una funcionalidad denominada scaffolding, que se encarga de crear en tiempo de ejecución una interfaz web tipo ABC (vista con Altas, Bajas y Cambios) para la clase de dominio indicada.

$ grails create-scaffold-controller mx.com.kinder.Estado
 
Esto generará la clase como sigue (Ojo, solo escoge uno de los dos comandos: create-controller ó create-scaffold-controller):
 
package mx.com.kinder

class EstadoController {

    static scaffold = Estado  //tambien funciona si colocas el valor: true
}

Esta funcionalidad se encargará de generar las operaciones abajo listadas para manipular los datos de esa entidad en la Base de Datos.  Es de notar que el controlador se llama igual que la clase de dominio, salvo por la terminación "Controller", esto es importante ya que se usa para determinar que esta clase es un controlador de la clase de dominio.  A pesar de que se tenga el scaffolding activado, se pueden sobreescribir los métodos para afinar su comportamiento.
  • list
  • show
  • edit
  • delete
  • create
  • save
  • update


Por último y antes de levantar nuestra aplicación quizá nos ayude tener algunos datos iniciales, por ejemplo de Catalogos como el de Estado (el cual solo contiene dos elementos ademas del identificador: el nombre y si esta activo).  Existe una clase Groovy que podemos usar para tal efecto: BootStrap.groovy y se implementaría mas o menos así:

import mx.com.kinder.Estado
class BootStrap {
  def init = { servletContext ->
    environments {
      development {
        if (!Estado.count()) {
          ["Aguascalientes", "Baja California", "Baja California Sur", "Campeche",
           "Coahuila de Zaragoza", "Colima", "Chiapas", "Chihuahua", "Distrito Federal",
           "Durango", "Guanajuato", "Guerrero", "Hidalgo", "Jalisco", "Mexico",
           "Michoacan de Ocampo", "Morelos", "Nayarit", "Nuevo Leon", "Oaxaca", "Puebla",
           "Queretaro de Arteaga", "Quintana Roo", "San Luis Potosi", "Sinaloa", "Sonora",
           "Tabasco", "Tamaulipas", "Tlaxcala", "Veracruz", "Yucatan", "Zacatecas"].each {
              new Estado(nombre: it, activo: true).save(failOnError: true)
           }
        }
      }
    }
  }
  def destroy = {}
}


Como ven, tiene dos fases; init se encarga de ejecutar el codigo dependiendo el ambiente indicado al levantar la aplicación y destroy trata de ejectuar algun proceso cuando la aplicación se dé de baja o por terminada.  En este caso estamos llenando de datos el catalogo de Estado solo si no existiese ningun dato en la tabla.

Si no se desea especificar ambiente, se puede prescindir de environments y el proceso lo ejecutará cuando levante para cualquier ambiente.

Casi  hemos terminado esta base de proyecto, tan solo falta generar las vistas, podemos hacer uso del comando generate-views para generar los archivos .gsp que hacen uso de jquery y hacen la funcion del Front (vista) al usuario de la aplicación.

$ grails generate-views mx.com.kinder.Estado
$ grails generate-views mx.com.kinder.Municipio 
$ grails generate-views mx.com.kinder.Postal 
$ grails generate-views mx.com.kinder.Alumno 
$ grails generate-views mx.com.kinder.Tutor
 
Cada comando generará una carpeta dentro de views con el nombre de cada clase de dominio y adentro 5 archivos .gsp: un template (_form.gsp), y cuatro paginas create.gsp, edit.gsp, list.gsp y show.gsp con el fin de lograr la funcionalidad ABC de cada clase de dominio.

JQuery

Si quieres jugar con este script, Grails 2.0.3 incluye como plugin por defecto la version 1.7.1 de jquery.  Pero para poder  acceder a sus funciones debes incluir la linea siguiente en el archivo /grails-app/views/layouts/main.gsp, dentro de la etiqueta <head> y antes de la línea que dice <r:layoutresources/> :

<g:javascript library="jquery" plugin="jquery"/> 
 
Luego, en cada página gsp donde quieras ejecutar codigo de jQuery debes incluir el siguiente script dentro de la etiqueta <head>, (si usas el clasico tag <script> no funcionará porque al momento de que Grails renderea la página, coloca este tag antes del include de la librería de jQuery, por lo que el código que coloques aquí no funcionará - por tanto es forzoso usar <g:javascript>):

    <g:javascript>
        $(document).ready(function() {
            alert('si funciona mi codigo de JQuery')
        })
    </g:javascript>

O la otra alternativa es:

    <r:script disposition='head'>
    </r:script>

Ambos scripts renderean a una etiqueta <script>, solo que <g:javascript> coloca el código dentro y al final de la etiqueta <body>, mientras que <r:script> lo coloca dentro de la etiqueta .

Ejecutar la aplicación

El comando run-app levanta la aplicación usando un tomcat con el puerto 8080 por defecto, pero se lo podemos cambiar si especificamos la variable "server.port".  Para salir debes dar CTL+C.

$ grails -Dserver.port=8090 run-app

Pero como esto no es lo óptimo para un ambiente de producción, sino instalarlo en un servidor aparte, podemos usar el comando war para generar el WAR con la configuración de producción por defecto y luego montarlo manualmente en cualquier servidor que soporte la version 2.5 de servlets (Por ejemplo: Tomcat,6,7; GlasFish 2,3; Resin 3,4; JBoss 5,6; Jetty 6,7; Websphere 6.1,7; Weblogic 9,10,10.3; SpringSourc tc Server).

Para ver la aplicación ejecutándose ve a la siguiente url:

http://localhost:8080/kinder

Se debería ver algo como esto.
 

Fuentes:

3 comentarios:

  1. muy bien, es muy buen aporte para comenzar a comprender el entorno de desarrollo de groovy-grails

    ResponderEliminar
  2. Buenos días, me gustaría que tengo que hacer para montar un war de grails en prod en algun servidor.

    ResponderEliminar
    Respuestas
    1. que tal Oscar, no se si entendi bien tu pregunta pero los war de grails se tratan igual que un war de java y se montan sombre un tomcat de la misma manera. Si quieres montarlo sobre un Application Server como Jboss, Websphere o Weblogic, entonces tendras que generar un ear que contenga el war dentro

      Eliminar

Que opinas sobre esta publicación?