Manuel Ángel Quindimil
@quindimildev
http://goo.gl/KpIYUo
http://goo.gl/KpIYUo
http://goo.gl/KpIYUo
http://goo.gl/KpIYUo
http://goo.gl/KpIYUo
$ grails create-app my-app
project name
http://goo.gl/KpIYUo
$ grails run-app
or using the gradle wrapper
$ ./gradlew bootRun
http://goo.gl/KpIYUo
Grails Object Relational Model
http://goo.gl/KpIYUo
Domain class could be also created directly into the domain folder
$ grails create-domain-class es.jbcnconf.Book
package es.jbcnconf
class Book {
String title
String isbn
String description
}
http://goo.gl/KpIYUo
Domain class could be also created directly into the domain folder
$ grails create-domain-class es.jbcnconf.Author
package es.jbcnconf
class Author {
String name
String email
}
http://goo.gl/KpIYUo
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
}
}
http://goo.gl/KpIYUo
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"
}
}
http://goo.gl/KpIYUo
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
}
}
http://goo.gl/KpIYUo
Include the JODB driver
dependencies {
// ...
runtime "mysql:mysql-connector-java:5.1.36"
// ...
}
build.gradle
http://goo.gl/KpIYUo
Setting DB configuration
application.yml
#..
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.jdbc.Driver
username: jbcnconf
password: jbcnconfpass
environments:
development:
dataSource:
dbCreate: create-drop
url: jdbc:mysql://localhost:3306/jbcndb
#..
http://goo.gl/KpIYUo
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 ->
author.addToBooks(title: "Book${authorIndex}-${bookIndex}",
description: "description ${authorIndex}-${bookIndex}")
}
author.save()
}
}
//to de when app is destroyed
def destroy = {
}
}
BootStrap.groovy
http://goo.gl/KpIYUo
Generates some basic CRUD interfaces for a domain class
$ grails generate-all *
http://goo.gl/KpIYUo
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
http://goo.gl/KpIYUo
We can add functionality installing plugins or create our own
http://goo.gl/KpIYUo
Installing Spring Security Core plugin
http://goo.gl/KpIYUo
dependencies {
// ...
compile 'org.grails.plugins:spring-security-core:3.1.1'
// ...
}
build.gradle
Setting the user and role classes
$ grails s2-quickstart es.jbcnconf User Role
http://goo.gl/KpIYUo
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'))
}
//..
http://goo.gl/KpIYUo
AuthorController.groovy
package es.jbcnconf
import grails.plugin.springsecurity.annotation.Secured
@Secured(['ROLE_ADMIN', 'ROLE_USER'])
class AuthorController {
//..
@Secured('ROLE_ADMIN')
def delete() { }
//..
}
http://goo.gl/KpIYUo
AuthorController.groovy
//..
grails.plugin.springsecurity.logout.postOnly = false
//..
http://goo.gl/KpIYUo
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
http://goo.gl/8s89PA
Running "create-app" the web profile is used by default
A profile encapsulates an application structure, set of commands, plugins and capabilities
http://goo.gl/8s89PA
How to use:
$ grails create-app my-rest-app --profile=rest-api
http://goo.gl/8s89PA
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.grails-web"
apply plugin: "org.grails.plugins.views-json"
//..
dependencies {
//..
compile 'org.grails.plugins:views-json'
//..
}
build.gradle
http://goo.gl/8s89PA
package es.jbcnconf
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.jbcnconf.AuthorService
http://goo.gl/8s89PA
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
http://goo.gl/8s89PA
import es.jbcnconf.Author
model{
Iterable<Author> authors
}
json tmpl.author(authors)
search.gson
Creating JSON Views
import es.jbcnconf.Author
model{
Author author
}
json{
name author.name
numBooks author.books.size()
}
_author.gson
..
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
http://goo.gl/KpIYUo
$ java -jar my-app-0.1.war
Runnable WAR
http://goo.gl/KpIYUo