#Grails
##Objetivo Simplifica el desarrollo de aplicaciones Java. Lleva el desarrollo de aplicaciones web al siguiente nivel de abstracción. Construido sobre muchas herramientas que son usadas actualmente y sigue teniendo la flexibilidad para cambiar lo que se desee. Las configuraciones por defecto son usualmente suficientes.
Hibernate | El ORM por default del mundo Java |
Spring | Inversion of Control (IoC) container y framework wrapper |
SiteMesh | Layout-rendering framework |
Tomcat | Embeddable servlet container |
H2 | RDBMS de Java |
Log4J | Logging |
ORM = Mapeo de object-oriented a relational databases IoC = Wiring de dependencia de objetos en runtime
##Core Ideas
###Convention over Configuration Pocos archivos de configuración. Muchos valores por defecto. Convenciones por directorio o nomenclatura. La convención no reemplaza a la configuración, es "over" y no "instead of".
Un controller llamado ShopController con una action llamada order |
Grails lo expone en la URL /app/shop/order |
Views en un directorio /views/shop/order |
Grails usa esas views para la action order del ShopController |
Clase Customer en la carpeta domain |
Grails crea una tabla llamada |
###Agile Philosophy Groovy! Código más corto, entendible y tweakeable. Iteración de desarrollo más fluida con reloading de recursos en runtime.
###Rock-solid Foundations Spring y Hibernate. Reliable y battle-tested. Muchísima documentación. Conocimiento previo de alguno no se pierde. Misma filosofía con plugins como Quartz, Lucene y Compass. Lo mismo con SiteMesh.
###Scaffolding and Templating Comandos simples y templates suficientes para aplicaciones básicas o bootsrapeos. Scaffolding genera views y controllers a partir del modelo para poder tener una aplicación funcionando en pocos minutos.
###Java Integration Hay problemas ya solucionados en Java con excelentes implementaciones, entonces por qué reinventar la rueda? Sabemos que un lenguaje con tipado estático es mejor para resolver ciertas tareas, por qué no usarlo? Se pueden usar todos los JARs o .java que se quieran.
###Incredible Community Comunidad muy activa, no solo de Grails sino de las tecnologías que usa. Wikis, mailing list, Twitter, podcasts, YouTube, etc.
###Productivity Ethos “Web apps come and go; zucchinis are forever.”
##Ejercicio
-
Crear la app con el comando
grails create-app qotd
-
Moverse al directorio creado con
cd qotd
-
Ejecutar la app con
grails run-app
-
Abrir un browser y navegar a http://localhost:8080/qotd
-
Detener la app con Ctrl + C,
grails stop-app
en otra terminal ostop-app
en modo interactivo -
Crear un controller con
grails create-controller quote
-
Agregar la action
home
def home() {
render "<h1>Real Programmers do not eat Quiche</h1>"
}
- Settear
home
como la default action del controller
static defaultAction = "home"
- Agregar la action
random
def random() {
def staticAuthor = "Anonymous"
def staticContent = "Real Programmers don't eat much quiche"
[ author: staticAuthor, content: staticContent]
}
- Agregar la view
random.gsp
para la actionrandom
<html>
<head>
<title>Random Quote</title>
</head>
<body>
<div id="quote">
<q>${content}</q>
<p>${author}</p>
</div>
</body>
</html>
-
Modificar el layout y settear un title genérico
-
Crear una domain class con
grails create-domain-class book
-
Agregar algunos fields
String title
String genre
String isbn
Date published = new Date()
-
Generar su controller y view con scaffolding con
grails generate-all qotd.Book
-
Cambiar a una base de datos en MySQL
development {
dataSource {
pooled = true
dbCreate = "create-drop"
url = "jdbc:mysql://localhost:3306/qotd"
driverClassName = "com.mysql.jdbc.Driver"
username = "root"
dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
}
hibernate
{
cache.use_second_level_cache = false
cache.use_query_cache = false
jdbc.batch_size = 50
loggingSql = true
}
}
- Agregar dependencia al connector de MySQL
dependencies {
runtime 'mysql:mysql-connector-java:5.1.32'
}
-
Crear una domain class con
grails create-domain-class quote
-
Agregar algunos fields
String content
String author
Date created = new Date()
-
Crear un test de integración para la domain class con
grails create-integration-test quote
-
Testear el guardado de quotes
def "Saving our first quote to the database"() {
given: "A brand new quote"
def quote = new Quote(author: 'blabla', content: 'blabla')
when: "The Quote is saved"
quote.save()
then: "It saved successfully and can be found in the database"
quote.errors.errorCount == 0
quote.id != null
Quote.get(quote.id).author == quote.author
}
- Agregar constraints a la domain class
static constraints = {
author nullable: false, blank: false
content maxSize: 1000, nullable: false, blank: false
}
- Testear las constraints
def "Trying to save a quote with invalid properties causes an error"() {
given: "A new quote without author"
def quote = new Quote(content: 'blabla')
when: "The Quote is validated"
quote.validate()
then: "It is not saved and error information can be obtained"
quote.hasErrors()
quote.errors.errorCount != 0
quote.id == null
!quote.errors.getFieldError('content')
quote.errors.getFieldError('author').code == 'nullable'
}
La solución del Ejercicio está en el repositorio: https://github.com/grailsinthecloud/qotd