Manuel Ángel Quindimil
@quindimildev
https://goo.gl/gzOHZb
https://goo.gl/gzOHZb
https://goo.gl/gzOHZb
https://goo.gl/gzOHZb
https://goo.gl/gzOHZb
$ grails create-app my-app
project name
https://goo.gl/gzOHZb
$ grails run-app
or using the gradle wrapper
$ ./gradlew bootRun
https://goo.gl/gzOHZb
Grails Object Relational Mapping
https://goo.gl/gzOHZb
Domain class could be also created directly into the domain folder
$ grails create-domain-class es.example.Book
package es.example
class Book {
String title
String isbn
String description
}
https://goo.gl/gzOHZb
Domain class could be also created directly into the domain folder
$ grails create-domain-class es.example.Author
package es.example
class Author {
String name
String email
}
https://goo.gl/gzOHZb
Defining validation rules, schema generation
class Book {
String title
String isbn
String description
static constraints = {
isbn nullable: true
}
}
class Author {
String name
String email
static constraints = {
email email: true, nullable: true
}
}
https://goo.gl/gzOHZb
Defining the way a domain is mapped to the DB
class Book {
String title
String isbn
String description
static constraints = {
isbn nullable: true
}
static mapping = {
table "books"
description type: "text"
}
}
https://goo.gl/gzOHZb
Creating a 1:n relation between two classes
class Book {
String title
String isbn
String description
static belongsTo = [author: Author]
static constraints = {
isbn nullable: true
}
static mapping = {
table "books"
description type: "text"
}
}
class Author {
String name
String email
static hasMany = [books: Book]
static constraints = {
email email: true, nullable: true
}
}
https://goo.gl/gzOHZb
Include the JDBC driver
dependencies {
// ...
runtime "mysql:mysql-connector-java:5.1.36"
// ...
}
build.gradle
https://goo.gl/gzOHZb
Setting DB configuration
application.yml
#..
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.jdbc.Driver
username: example
password: example
environments:
development:
dataSource:
dbCreate: create-drop
url: jdbc:mysql://localhost:3306/example
#..
https://goo.gl/gzOHZb
Programmatic start-up configuration can be added
class BootStrap {
//to do when app is launched
def init = { servletContext ->
50.times{ authorIndex ->
Author author = new Author(name: "Author ${authorIndex}",
email: "email${authorIndex}@salenda.es")
3.times{ bookIndex ->
Book book = new Book(title: "Book${authorIndex}-${bookIndex}",
description: "description ${authorIndex}-${bookIndex}")
author.addToBooks(book)
}
author.save()
}
}
//to de when app is destroyed
def destroy = {
}
}
BootStrap.groovy
https://goo.gl/gzOHZb
Generates some basic CRUD interfaces for a domain class
$ grails generate-all "*"
https://goo.gl/gzOHZb
If we do not want to use it....
dependencies {
// ...
//remove this
compile "org.grails.plugins:scaffolding"
// ...
}
build.gradle
Do not remove it if you have used cause includes some required dependencies
https://goo.gl/gzOHZb
We can add functionality installing plugins or create our own
https://goo.gl/gzOHZb
Installing Spring Security Core plugin
https://goo.gl/gzOHZb
dependencies {
// ...
compile 'org.grails.plugins:spring-security-core:3.1.1'
// ...
}
build.gradle
Setting the user and role classes
$ grails s2-quickstart es.example User Role
https://goo.gl/gzOHZb
BootStrap.groovy
//..
if(!Role.count){
['ROLE_ADMIN', 'ROLE_USER'].each{ roleName ->
new Role(authority: roleName).save(flush:true)
}
}
if(!User.count){
User admin = new User(username: 'admin', password: 'admin')
admin.save(flush: true, failOnError: true)
UserRole.create(admin, Role.findByAuthority('ROLE_ADMIN'))
User user = new User(username: 'user', password: 'user')
user.save(flush: true, failOnError: true)
UserRole.create(user, Role.findByAuthority('ROLE_USER'))
}
//..
https://goo.gl/gzOHZb
AuthorController.groovy
package es.example
import grails.plugin.springsecurity.annotation.Secured
@Secured(['ROLE_ADMIN', 'ROLE_USER'])
class AuthorController {
//..
@Secured('ROLE_ADMIN')
def delete() { }
//..
}
https://goo.gl/gzOHZb
AuthorController.groovy
//..
grails.plugin.springsecurity.logout.postOnly = false
//..
Logout is only allow by default but can be set
//..
//We haven't created this 'email' property yet!
grails.plugin.springsecurity.userLookup.usernamePropertyName = 'email'
//..
Changing login by username for other user property instead
application.groovy
application.groovy
https://goo.gl/gzOHZb
Running "create-app" the web profile is used by default
A profile encapsulates an application structure, set of commands, plugins and capabilities
https://goo.gl/gzOHZb
How to use:
$ grails create-app my-rest-app --profile=rest-api
https://goo.gl/gzOHZb
Comes by default with the rest-api profile
but we can use them on our app with web profile
buildscript {
//..
dependencies {
//..
classpath "org.grails.plugins:views-gradle:1.0.12"
}
}
//Insert after Grails core gradle plugins
apply plugin: "org.grails.plugins.views-json"
//..
dependencies {
//..
compile 'org.grails.plugins:views-json'
//..
}
build.gradle
https://goo.gl/gzOHZb
package es.example
import grails.transaction.Transactional
@Transactional
class AuthorService {
def search(String name, String email) {
// Dynamic finders are the easiest way for retrieving data from DB
// Author.findAllByNameLike("%${name}%")
// Criterias have better performance, and do more complex queries
Author.withCriteria{
like("name", "%${name}%")
if(email){
like("email", "%${email}%")
}
}
}
}
AuthorService.groovy
Creating a service for searching Authors
$ grails create-service es.example.AuthorService
https://goo.gl/gzOHZb
Injecting the service bean in the controller
//@Secured(['ROLE_ADMIN', 'ROLE_USER'])
@Secured('permitAll')
class AuthorController {
AuthorService authorService
//..
def search(){
[authors: authorService.search(params.name, params.email)]
}
AuthorController.groovy
Allowing free access to the controller
Invokes the service method
The request parameters map
Creating an action
https://goo.gl/gzOHZb
import es.example.Author
model{
Iterable<Author> authors
}
json tmpl.author(authors)
search.gson
Creating JSON Views with a template
import es.example.Author
model{
Author author
}
json{
name author.name
numBooks author.books.size()
}
_author.gson
https://goo.gl/gzOHZb
..
version "0.1"
..
build.gradle
Specifying the app version
Building a runnable war
$ grails dev package
$ ./gradlew assemble -Dgrails.env=dev
or using the gradle wrapper
https://goo.gl/gzOHZb
$ java -jar my-app-0.1.war
Runnable WAR
https://goo.gl/gzOHZb