SlideShare uma empresa Scribd logo
1 de 59
Baixar para ler offline
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 1
© Copyright 2010, Software Alchemy
Getting Groovy with Grails
Bryan Basham
Software Alchemy
basham47@gmail.com
http://www.linkedin.com/in/SoftwareAlchemist
Grails
Architecture
Getting
Groovy w/
Grails
Domain
Modeling
Getting
Started
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 2
© Copyright 2010, Software Alchemy
Grails
Architecture
Domain
Modeling
Getting
Groovy w/
Grails
Install
Grails
Create
App
Create
Entity
GUI Scaffolding
Basic
Domain
Modeling
Getting
Started
Getting Started
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 3
© Copyright 2010, Software Alchemy
Install Grails
● Download Grails at http://www.grails.org/
– I am using version 1.3.4 for this tech talk
● Unpack ZIP file on computer
● Set GRAILS_HOME environment variable
● Add $GRAILS_HOME/bin to PATH
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 4
© Copyright 2010, Software Alchemy
Create a Grails App
● Execute command, eg:
grails create-app MyApp
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 5
© Copyright 2010, Software Alchemy
MyApp Use Cases
List employees
Update employee
Create employee
Retrieve employee
Delete employee
Classic CRUD
Operations
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 6
© Copyright 2010, Software Alchemy
Create a Domain Entity
● Create the Employee domain class, eg:
grails create-domain-class com.example.Employee
package com.example
class Employee {
String firstName
String lastName
Integer age
static constraints = {
}
}
«entity»
Employee
{from com.example}
firstName : String
lastName : String
age : Integer
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 7
© Copyright 2010, Software Alchemy
Create a GUI Controller
● Create the Employee controller class, eg:
grails create-controller com.example.Employee
package com.example
class EmployeeController {
def scaffold = Employee
}
● Grails scaffolding provides all basic CRUD
operations and GUI Views
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 8
© Copyright 2010, Software Alchemy
Default GUI Scaffolding
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 9
© Copyright 2010, Software Alchemy
Default GUI Scaffolding (2)
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 10
© Copyright 2010, Software Alchemy
Default GUI Scaffolding (3)
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 11
© Copyright 2010, Software Alchemy
Behind the Looking Glass
● Create the Employee GUI controller class:
grails generate-controller com.example.Employee
class EmployeeController {
def index = {
redirect(action: "list", params: params)
}
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[employeeList: Employee.list(params),
employeeTotal: Employee.count()]
}
def save = {
def employee = new Employee(params)
if (employee.save(flush: true)) {
flash.message = "Employee ${employee.id} created."
redirect(action: "show", id: employee.id)
} else {
render(view: "create", model: [employeeInstance: employee])
}
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 12
© Copyright 2010, Software Alchemy
Behind the Looking Glass (2)
● Create the Employee GUI views:
grails generate-views com.example.Employee
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 13
© Copyright 2010, Software Alchemy
Behind the Looking Glass (3)
● The list.gsp View:
<table>
<tbody>
<g:each in="${employeeList}" status="i" var="employee">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td><g:link action="show" id="${employee.id}">
${fieldValue(bean: employee, field: "id")}</g:link>
</td>
<td>${fieldValue(bean: employee, field: "age")}</td>
<td>${fieldValue(bean: employee, field: "firstName")}</td>
<td>${fieldValue(bean: employee, field: "lastName")}</td>
</tr>
</g:each>
</tbody>
</table>
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 14
© Copyright 2010, Software Alchemy
Behind the Looking Glass (4)
● The create.gsp View:
<g:form action="save" >
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="age"><g:message code="employee.age.label" default="Age"
/></label>
</td>
<td valign="top" class="value ${hasErrors(bean: employeeInstance, field:
'age', 'errors')}">
<g:textField name="age" value="${fieldValue(bean: employeeInstance,
field: 'age')}" />
</td>
</tr>
...
</tbody>
</table>
</g:form>
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 15
© Copyright 2010, Software Alchemy
A Simple Relationship
class Employee {
String firstName
String lastName
Integer age
Department department
static constraints = {
}
}
«entity»
Department
{from com.example}
name : String
«entity»
Employee
{from com.example}
firstName : String
lastName : String
age : Integer
department
10..*
class Department {
String name
static constraints = {
}
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 16
© Copyright 2010, Software Alchemy
Create GUI components
● Create Department GUIs and recreate
Employee GUIs
A drop-down list of
department objects,
but the names are
weird.
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 17
© Copyright 2010, Software Alchemy
Fix Department Display
● Add a simple toString method:
class Department {
String name
String toString() { name }
static constraints = {
}
}
The toString method is used to
create a useful display name.
You could also create custom
GSP code for the drop-down list
widget.
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 18
© Copyright 2010, Software Alchemy
Grails
Architecture
Conv/Config
Build
tools
Web techPlugins
Groovy
Getting
Groovy w/
Grails
Domain
Modeling
Install
Grails
Create
App
Create
Entity
GUI Scaffolding
Basic
Domain
Modeling
Getting
Started
Grails Architecture
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 19
© Copyright 2010, Software Alchemy
Grails Technology Stack
The Java Virtual Machine
Groovy
Java Lang / JRE JDK
Grails
JavaEE Spring Hibernate SiteMesh
Plugins...
Your Grails Application
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 20
© Copyright 2010, Software Alchemy
Groovy Quick Look
● Groovy is a scripting langage on top of Java
● Syntax for lists and maps:
– [1, 2, 3]
– [foo:1, bar:2, baz:3]
● Closures:
– [1, 2, 3].collect { it * it } => [1, 4, 9]
● Fancy Strings:
– 'foo' is a Java String
– “foo is ${map.foo}” is a GString
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 21
© Copyright 2010, Software Alchemy
Groovy Quick Look (2)
● Groovy classes are JavaBeans
class Employee {
String name
Integer age
}
● Setter/Getters are auto created unless
specified:
class Employee {
String name
Date dateOfBirth
Integer getAge() { /* calc age from DoB */ }
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 22
© Copyright 2010, Software Alchemy
Convention over Configuration
● Configuration is kept to a bare minimum
● Convention abounds:
– Entities
– Controllers and URL patterns
– Services and dependency injection
– Tag libraries
– Scaffolding
– and much more
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 23
© Copyright 2010, Software Alchemy
Logging
● Configure logging in grails-app/conf/
Config.groovy file:
log4j = {
root {
info 'stdout'
additivity = true
}
info 'com.example'
// more configuration snipped
}
● Log objects automatically available:
if (employeeInstance.save(flush: true)) {
log.info "Employee ${employeeInstance.id} created."
redirect(action: "show", id: employeeInstance.id)
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 24
© Copyright 2010, Software Alchemy
Data Sources
● Configured in the grails-app/conf/
DataSource.groovy file
● Database driver JAR file configured in the
grails-app/conf/BuildConfig.groovy file
● Must create the database before using, but
schema creation is handled by Grails
– Use create-drop to create the DB on every run
– This option destroys any data stored
– Typically used during rapid prototyping
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 25
© Copyright 2010, Software Alchemy
Example: MySQL
● DataSource.groovy:
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-
drop','update'
url = "jdbc:mysql://localhost:8889/my-app-db"
driverClassName = "com.mysql.jdbc.Driver"
username = "root"
password = "root"
}
}
● BuildConfig.groovy:
dependencies {
runtime 'mysql:mysql-connector-java:5.1.12'
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 26
© Copyright 2010, Software Alchemy
Pre-populate DB
● Pre-populate the database using the grails-
app/conf/BootStrap.groovy file:
import com.example.Department;
class BootStrap {
def init = { servletContext ->
if ( Department.count() == 0 ) {
new Department(name:"Accounting").save()
new Department(name:"Marketing").save()
new Department(name:"Development").save()
new Department(name:"Sales").save()
}
}
def destroy = {
}
}
The count() method is
like the SQL statement:
SELECT count(*)
FROM department
The save() method is
like an SQL INSERT
statement.
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 27
© Copyright 2010, Software Alchemy
Eclipse Integration
● Install the Groovy plugin:
http://dist.springsource.org/release/GRECLIPSE/e3.6/
● Groovy support in Eclipse is spotty but
workable
– Hard to find all necessary libraries
– No obvious access to source or javadocs
– Debugging Grails apps is very difficult
● Maven helps with some of these issues
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 28
© Copyright 2010, Software Alchemy
Maven Integration
● Creating a Grails app with Maven 2:
mvn archetype:generate -DarchetypeGroupId=org.grails 
-DarchetypeArtifactId=grails-maven-archetype 
-DarchetypeVersion=1.3.4 
-DgroupId=com.example -Dversion=0.1 -DartifactId=MyMavenApp
cd MyMavenApp/
mvn initialize
● Supporting Eclipse:
mvn -DdownloadSources=true -DdownloadJavadocs=true 
eclipse:eclipse
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 29
© Copyright 2010, Software Alchemy
Ant Integration
● You can use Grails scripts in an Ant script
● You can use Ant tasks in your own Grails
scripts, Example:
ant.property(file:"${basedir}/application.properties")
def appName = "${Ant.project.properties['app.name']}"
def appVersion = "${Ant.project.properties['app.version']}"
def appPath = "${appName}-${appVersion}"
target(main: "Create an archive of the complete project source.") {
ant.zip(destfile: "../${appPath}-dist.zip") {
zipfileset(dir:"${basedir}", prefix:"${appPath}") {
exclude(name:"target/**")
exclude(name:"web-app/WEB-INF/classes/**")
}
}
}
setDefaultTarget(main)
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 30
© Copyright 2010, Software Alchemy
External Deployment
● Build a WAR file using this command:
grails dev war
● Deploy to your JavaEE compilant web
container
– WAR includes all Groovy and Grails JARs
– WAR includes all infrastructure JARs
– WAR includes DB driver JAR
– WAR includes all plugins
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 31
© Copyright 2010, Software Alchemy
Web Technologies
● Controllers
● Views: GSPs
● Tag libraries
● Filters
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 32
© Copyright 2010, Software Alchemy
Controllers
● Controllers are Groovy classes that reside in
the grails-app/controllers source directory
● Method names map to URL patterns, eg:
http://localhost:8080/MyApp/employee/list
– Maps to EmployeeController and list method
● View selection:
– Use render to render a specific View component
– Use redirect to tell the browser to redirect
– Return a model Map to render this method's
View, eg. list action renders list.gsp
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 33
© Copyright 2010, Software Alchemy
Views: GSPs
● Very much like JSPs but uses Groovy as the
scripting language; cavet: don't script!
● Use custom tags for view logic
– Large built-in library
– Easy to create your own
● GSP attributes:
– standard JSP attribute scopes plus flash scope
– named values in the action method's model Map
● Grails uses SiteMesh for layout control
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 34
© Copyright 2010, Software Alchemy
Tag Libraries
● Tag libraries are Groovy classes that reside in
the grails-app/taglib source directory
● Each method provides a custom tag, eg:
class MyTags {
def isAdmin = { attrs, body ->
def user = attrs['user']
if ( user != null && checkUserPrivs(user) ) {
out << body()
}
}
}
● No configuration required
● Automatically available in all GSPs, eg:
<g:isAdmin user=”${theUser}”>ADMIN CONTENT</g:isAdmin>
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 35
© Copyright 2010, Software Alchemy
Request Filters
● Filters are Groovy classes that reside in the
grails-app/conf source directory that end in
Filters
class SecurityFilters {
def filters = {
loginCheck(controller:'*', action:'*') {
before = {
if (params.controller == null) {
redirect(action:'login')
return true
} else if(!session.user && !actionName.equals('login')) {
redirect(action:'login')
return false
}
}
}
}
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 36
© Copyright 2010, Software Alchemy
Transactions and Services
● Controller actions can be made transactional
– Use Spring SessionFactory injection
– Or use the withTransaction method
● Service components are a better solution
– All classes that reside in the grails-
app/services source directory
– Use the def transactional = true for Spring
transaction AOP wrapping
– Inject the service into the controller:
def storeService // auto-injects StoreService
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 37
© Copyright 2010, Software Alchemy
Plugins
● Grails is a framework built on plugins
● Default plugins:
– Hibernate: the Grails ORM (aka GORM)
– Tomcat: the Grails default runtime environment
● Hundreds of additional plugins
– Security (40)
– Services (117)
– JavaScript frameworks (74)
– many more...
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 38
© Copyright 2010, Software Alchemy
Spring Security Plugin
● Install the plugin:
grails install-plugin spring-security-core
● Create the User and Role entities:
grails s2-quickstart com.example.security User Role
«javaPackage»
com.example.security
«entity»
Role
authority : String
«entity»
User
username : String
password : String
enabled : boolean role
1
0..*
«entity»
UserRoleuser
1
/+authorities
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 39
© Copyright 2010, Software Alchemy
BootStrap Roles and Users
import com.example.security.*;
class BootStrap {
def springSecurityService
def init = { servletContext ->
// Define user role's
def hrRepRole = Role.findByAuthority('ROLE_HR_REP') ?: new
Role(authority: 'ROLE_HR_REP').save(failOnError: true)
def hrMgrRole = Role.findByAuthority('ROLE_HR_MANAGER') ?: new
Role(authority: 'ROLE_HR_MANAGER').save(failOnError: true)
def adminRole = Role.findByAuthority('ROLE_ADMIN') ?: new
Role(authority: 'ROLE_ADMIN').save(failOnError: true)
// a few users:
def adminUser = User.findByUsername('admin') ?: new User(
username: 'admin',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true)
if (!adminUser.authorities.contains(adminRole)) {
UserRole.create adminUser, adminRole
}
// and so on
}
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 40
© Copyright 2010, Software Alchemy
Define Security Constraints
● Use annotations on controller actions, eg:
import grails.plugins.springsecurity.Secured
class DepartmentController {
@Secured(['ROLE_HR_MANAGER', 'ROLE_HR_REP'])
def list = { ... }
@Secured(['ROLE_HR_MANAGER'])
def create = { ... }
@Secured(['ROLE_ADMIN'])
def delete = { ... }
}
● Or static URL rules in the Config.groovy file
● Or store the rules in the database
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 41
© Copyright 2010, Software Alchemy
Grails
Architecture
Conv/Config
Build
tools
Web techPlugins
Groovy
Getting
Groovy w/
Grails
Install
Grails
Create
App
Create
Entity
GUI Scaffolding
Basic
Domain
Modeling
Getting
Started
Domain
Modeling
Relationships
Validation
Enumerated
types
Derived
properties
Embedded
properties
Inheritance
Domain Modeling
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 42
© Copyright 2010, Software Alchemy
HrApp Use Cases
View HR action history
Employee
Manager
HR Rep
HR Mgr
View department staff
Promote employee
Issue pay raise for employee
Confirm employee promotion
Confirm employee pay raise
Issue cost-of-living raise to department
Hire employee
Terminate employee
Confirm employee hire
Confirm employee termination
Confirm department COL raise
Create/update job roles
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 43
© Copyright 2010, Software Alchemy
Domain Model is King!
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 44
© Copyright 2010, Software Alchemy
Property Validations
● Property constraints are defined in the Domain
model, eg:
class Employee {
// skipping property definitions
static constraints = {
firstName(nullable:false, blank:false, maxSize:32)
lastName(nullable:false, blank:false, maxSize:64)
dateOfBirth(nullable:true)
homeAddress(nullable:false)
homePhone(nullable:false)
cellPhone(nullable:true)
department(nullable:false)
jobRole(nullable:true)
salary(nullable:true, min:10000)
proposedChange(nullable:true)
// workflow properties
user(nullable:false)
status(nullable:false)
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 45
© Copyright 2010, Software Alchemy
Basic Enumerated Types
● Grails supports Java-style enums, eg:
class Employee {
// other properties
Status status
enum Status {
CREATED,
HIRED,
DISCIPLINARY_REVIEW,
TERMINATED;
static def getActiveStatuses = {
return [HIRED, DISCIPLINARY_REVIEW]
}
}
// more code
}
● ...but the enum name is stored in the DB field
which is a bit wasteful, so...
«enumeratedType»
Status
+CREATED
+HIRED
+DISCIPLARY_REVIEW
+TERMINATED
«entity»
Employee
firstName : String
lastName : String
...
status : Status
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 46
© Copyright 2010, Software Alchemy
Enumerated Types with Ids
● You can define an id field in the enum, eg:
class EmployeeAction {
// other properties
enum ActionType {
HIRE('HI'),
RAISE('RA'),
COL_RAISE('CR'),
PROMOTE('PO'),
TERMINATE('TE');
final String id
ActionType(String id) {
this.id = id
}
}
// more code
}
● ...so now the DB field is a two-char value.
«enumeratedType»
Status
+HIRE('HI')
+RAISE('RA')
+COL_RAISE('CR')
+PROMOTE('PO')
+TERMINATE('TE')
id : String
«entity»
EmployeeAction
type : ActionType
employee : Employee
newRole : JobRole
...
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 47
© Copyright 2010, Software Alchemy
Derived Properties
● Also know as transient properties, eg:
class Employee {
// Properties
Date dateOfBirth
// Derived properties
Integer getAge() {
// corner case
if ( dateOfBirth == null ) return null;
// calculate and memoize the employee's age
_age = _age ?: DateUtils.dateDiffYears(new Date(), dateOfBirth)
return _age
}
private Integer _age
// GORM constraints
static transients = [ 'age', ... ]
}
«entity»
Employee
dateOfBirth : Date
/age : Integer
...
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 48
© Copyright 2010, Software Alchemy
Derived Relationships
● You can do the same with computed
relationships, eg:
class Employee {
// Derived properties
List<EmployeeAction> getHistory() {
// calculate and memoize the employee's HR history
_history = _history ?: EmployeeAction.findAllByEmployee( this,
[sort:'proposedDate', order:'asc'] )
return _history
}
private List<EmployeeAction> _history
// GORM constraints
static transients = [ 'age', 'history', ... ]
}
«entity»
EmployeeAction/history
*«entity»
Employee
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 49
© Copyright 2010, Software Alchemy
Embedded Properties
● Grails encourages rich object models even for
non-Entity objects, eg:
class Employee {
// Properties
Address homeAddress
PhoneNumber homePhone
PhoneNumber cellPhone
// GORM constraints
static embedded = [ 'homeAddress', 'homePhone', 'cellPhone' ]
}
class PhoneNumber {
// Properties
String areaCode
String prefix
String number
// GORM constraints...
}
«entity»
Employee
homeAddress : Address
homePhone : PhoneNumber
cellPhone : PhoneNumber
«valueObject»
PhoneNumber
areaCode : String
prefix : String
number : String
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 50
© Copyright 2010, Software Alchemy
Embedded Properties (2)
● GORM creates a DB schema with each field of
the Value Object embedded in the fields of the
Entity.
class Employee {
// Properties
Address homeAddress
PhoneNumber homePhone
PhoneNumber cellPhone
}
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 51
© Copyright 2010, Software Alchemy
Relationships
● Grails supports: one-to-one, one-to-many and
many-to-many
● Grails supports uni- and bi-directional
relationships
● Grails support ownership, with cascading
deletes
● Grails supports unordered sets, sorted sets,
and lists (with ordering index)
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 52
© Copyright 2010, Software Alchemy
One-to-One Relationships
class Employee {
// Properties
Department department
JobRole jobRole
User user
// GORM constraints
static constraints = {
department(nullable:false)
jobRole(nullable:true)
user(nullable:false)
}
«entity»
JobRolejobRole
0..1
«entity»
User
{from com.example.security}
user1
«entity»
Employee
user : User
jobRole : JobRole
department : Department
«entity»
Department department
1
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 53
© Copyright 2010, Software Alchemy
One-to-Many
class HRRepresentative extends Employee {
// Properties
Set<Department> departments
// GORM constraints
static hasMany = [ 'departments' : Department ]
}
«entity»
HRRepresentative
departments : Set<Department>
«entity»
Department departments
*
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 54
© Copyright 2010, Software Alchemy
Inheritance
● Inheritance is supported with little to no
configuration
● By default, the whole hierarchy is stored in one
table
● You can configure Grails to use multiple tables
● ...but be aware of the DB performance impact
of multiple selects and table joins
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 55
© Copyright 2010, Software Alchemy
Inheritance (2)
class Employee { ... }
class HRRepresentative extends Employee { ... }
class Manager extends Employee { ... }
class Engineer extends Employee { ... }
«entity»
Employee
«entity»
HRRepresentative
«entity»
Manager
«entity»
Engineer
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 56
© Copyright 2010, Software Alchemy
Inheritance (3)
● The resulting DB table:
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 57
© Copyright 2010, Software Alchemy
Grails
Architecture
Conv/Config
Build
tools
Web techPlugins
Groovy
Getting
Groovy w/
Grails
Install
Grails
Create
App
Create
Entity
GUI Scaffolding
Basic
Domain
Modeling
Getting
Started
Domain
Modeling
Relationships
Validation
Enumerated
types
Derived
properties
Embedded
properties
Inheritance
Q & A
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 58
© Copyright 2010, Software Alchemy
Ten Great Topics Not Covered
1) Supports unit and integration testing
2) Supports RESTful URL patterns
3) Supports Java and Spring integration
4) Supports multiple environments
5) Integration to legacy DBs using Hibernate mappings
6) Supports turning Service components into Web Services
7) Easy to create your own plugins for cross-team sharing
8) Supports other continuous integration tools: Hudson, Ivy, etc
9) Supports data auditing and time stamping w/ GORM event
model
10) Supports Ajax and Spring Web Flows
Rochester JUG: 9-Nov-2010
Bryan Basham – Getting Groovy with Grails Slide 59
© Copyright 2010, Software Alchemy
Resources
● Groovy (http://groovy.codehaus.org/)
– Reference docs (click here)
– Reference card (click here)
● Grails (http://www.grails.org/)
– Reference docs (click here)
● Eclipse plugin
(http://dist.springsource.org/release/GRECLIPSE/e3.6/)
● The Definitive Guide to Grails (by Rocher and
Brown, Apress)

Mais conteúdo relacionado

Destaque

Ifugao antipolo bible - new testament
Ifugao  antipolo bible - new testamentIfugao  antipolo bible - new testament
Ifugao antipolo bible - new testamentBiblesForYOU
 
Rebel Prabhas speaks on his surgery
Rebel Prabhas speaks on his surgery   Rebel Prabhas speaks on his surgery
Rebel Prabhas speaks on his surgery telugustop.com
 
Tesis doctoral: la influencia mediática en la formulación de la política crim...
Tesis doctoral: la influencia mediática en la formulación de la política crim...Tesis doctoral: la influencia mediática en la formulación de la política crim...
Tesis doctoral: la influencia mediática en la formulación de la política crim...Doctor Joaquin Medina Bermejo
 
34.muatan haba pendam tentu
34.muatan haba pendam tentu34.muatan haba pendam tentu
34.muatan haba pendam tentuAtiqah Azmi
 
Guía taller n1 sesión 4 family the family and their occupations no 4
Guía taller n1 sesión 4 family   the family and their occupations no 4Guía taller n1 sesión 4 family   the family and their occupations no 4
Guía taller n1 sesión 4 family the family and their occupations no 4Institución Educativa Simón Bolívar
 
Discussion on the legitimacy source of Court Judge
Discussion on the legitimacy source of Court JudgeDiscussion on the legitimacy source of Court Judge
Discussion on the legitimacy source of Court JudgeDennis Chen
 
State of jQuery '08
State of jQuery '08State of jQuery '08
State of jQuery '08jeresig
 
X2 t06 06 banked curves (2012)
X2 t06 06 banked curves (2012)X2 t06 06 banked curves (2012)
X2 t06 06 banked curves (2012)Nigel Simmons
 
FabLearnAsia 2015 
FabLearnAsia 2015 FabLearnAsia 2015 
FabLearnAsia 2015 Kadota Kazuo
 
jQuery Open Source (Fronteer 2011)
jQuery Open Source (Fronteer 2011)jQuery Open Source (Fronteer 2011)
jQuery Open Source (Fronteer 2011)jeresig
 
Política criminológica derechos humanos dyc
Política criminológica derechos humanos dycPolítica criminológica derechos humanos dyc
Política criminológica derechos humanos dycWael Hikal
 
actividad 3
actividad 3actividad 3
actividad 3dhz96
 
La Vasija Agrietada Diapositivas
La Vasija Agrietada DiapositivasLa Vasija Agrietada Diapositivas
La Vasija Agrietada Diapositivasavapla81
 
Flujograma jesus granda
Flujograma jesus grandaFlujograma jesus granda
Flujograma jesus grandajesus_granda07
 
Mobile Errai
Mobile ErraiMobile Errai
Mobile Erraiejdewit
 
Fundamentos del-ajuste-a-los-marcos-curriculares
Fundamentos del-ajuste-a-los-marcos-curricularesFundamentos del-ajuste-a-los-marcos-curriculares
Fundamentos del-ajuste-a-los-marcos-curricularesHector Luengo Rodriguez
 
La onu advierte que la brecha digital crece
La onu advierte que la brecha digital creceLa onu advierte que la brecha digital crece
La onu advierte que la brecha digital crecelaycar
 

Destaque (20)

pri12178_PLW 2012.pdf
pri12178_PLW 2012.pdfpri12178_PLW 2012.pdf
pri12178_PLW 2012.pdf
 
Ifugao antipolo bible - new testament
Ifugao  antipolo bible - new testamentIfugao  antipolo bible - new testament
Ifugao antipolo bible - new testament
 
Rebel Prabhas speaks on his surgery
Rebel Prabhas speaks on his surgery   Rebel Prabhas speaks on his surgery
Rebel Prabhas speaks on his surgery
 
Tesis doctoral: la influencia mediática en la formulación de la política crim...
Tesis doctoral: la influencia mediática en la formulación de la política crim...Tesis doctoral: la influencia mediática en la formulación de la política crim...
Tesis doctoral: la influencia mediática en la formulación de la política crim...
 
34.muatan haba pendam tentu
34.muatan haba pendam tentu34.muatan haba pendam tentu
34.muatan haba pendam tentu
 
Guía taller n1 sesión 4 family the family and their occupations no 4
Guía taller n1 sesión 4 family   the family and their occupations no 4Guía taller n1 sesión 4 family   the family and their occupations no 4
Guía taller n1 sesión 4 family the family and their occupations no 4
 
Discussion on the legitimacy source of Court Judge
Discussion on the legitimacy source of Court JudgeDiscussion on the legitimacy source of Court Judge
Discussion on the legitimacy source of Court Judge
 
State of jQuery '08
State of jQuery '08State of jQuery '08
State of jQuery '08
 
X2 t06 06 banked curves (2012)
X2 t06 06 banked curves (2012)X2 t06 06 banked curves (2012)
X2 t06 06 banked curves (2012)
 
FabLearnAsia 2015 
FabLearnAsia 2015 FabLearnAsia 2015 
FabLearnAsia 2015 
 
jQuery Open Source (Fronteer 2011)
jQuery Open Source (Fronteer 2011)jQuery Open Source (Fronteer 2011)
jQuery Open Source (Fronteer 2011)
 
Política criminológica derechos humanos dyc
Política criminológica derechos humanos dycPolítica criminológica derechos humanos dyc
Política criminológica derechos humanos dyc
 
actividad 3
actividad 3actividad 3
actividad 3
 
La Vasija Agrietada Diapositivas
La Vasija Agrietada DiapositivasLa Vasija Agrietada Diapositivas
La Vasija Agrietada Diapositivas
 
Communitydays2015
Communitydays2015Communitydays2015
Communitydays2015
 
Flujograma jesus granda
Flujograma jesus grandaFlujograma jesus granda
Flujograma jesus granda
 
Mobile Errai
Mobile ErraiMobile Errai
Mobile Errai
 
SmarArt
SmarArt SmarArt
SmarArt
 
Fundamentos del-ajuste-a-los-marcos-curriculares
Fundamentos del-ajuste-a-los-marcos-curricularesFundamentos del-ajuste-a-los-marcos-curriculares
Fundamentos del-ajuste-a-los-marcos-curriculares
 
La onu advierte que la brecha digital crece
La onu advierte que la brecha digital creceLa onu advierte que la brecha digital crece
La onu advierte que la brecha digital crece
 

Semelhante a Getting Groovy With Grails

G*なクラウド ~雲のかなたに~
G*なクラウド ~雲のかなたに~G*なクラウド ~雲のかなたに~
G*なクラウド ~雲のかなたに~Tsuyoshi Yamamoto
 
Introduction to Cloud Computing with Google Cloud
Introduction to Cloud Computing with Google CloudIntroduction to Cloud Computing with Google Cloud
Introduction to Cloud Computing with Google Cloudwesley chun
 
G*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョンG*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョンTsuyoshi Yamamoto
 
How To Build a Multi-Field Search Page For Your XPages Application
How To Build a Multi-Field Search Page For Your XPages ApplicationHow To Build a Multi-Field Search Page For Your XPages Application
How To Build a Multi-Field Search Page For Your XPages ApplicationMichael McGarel
 
Groovy Grails Gr8Ladies Women Techmakers: Minneapolis
Groovy Grails Gr8Ladies Women Techmakers: MinneapolisGroovy Grails Gr8Ladies Women Techmakers: Minneapolis
Groovy Grails Gr8Ladies Women Techmakers: MinneapolisJenn Strater
 
Spring boot 3g
Spring boot 3gSpring boot 3g
Spring boot 3gvasya10
 
Lambda Architecture using Google Cloud plus Apps
Lambda Architecture using Google Cloud plus AppsLambda Architecture using Google Cloud plus Apps
Lambda Architecture using Google Cloud plus AppsSimon Su
 
Open Source - NOVALUG January 2019
Open Source  - NOVALUG January 2019Open Source  - NOVALUG January 2019
Open Source - NOVALUG January 2019plarsen67
 
The Grails introduction workshop
The Grails introduction workshopThe Grails introduction workshop
The Grails introduction workshopGR8Conf
 
An open-source TIMES/MIRO app
An open-source TIMES/MIRO appAn open-source TIMES/MIRO app
An open-source TIMES/MIRO appIEA-ETSAP
 
Grunt training deck
Grunt training deckGrunt training deck
Grunt training deckJames Ford
 
Bluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part IBluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part IJoseph Chang
 
Automating Front-End Workflow
Automating Front-End WorkflowAutomating Front-End Workflow
Automating Front-End WorkflowDimitris Tsironis
 
Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsDylan Jay
 

Semelhante a Getting Groovy With Grails (20)

Django introduction
Django introductionDjango introduction
Django introduction
 
G*なクラウド ~雲のかなたに~
G*なクラウド ~雲のかなたに~G*なクラウド ~雲のかなたに~
G*なクラウド ~雲のかなたに~
 
Introduction to Cloud Computing with Google Cloud
Introduction to Cloud Computing with Google CloudIntroduction to Cloud Computing with Google Cloud
Introduction to Cloud Computing with Google Cloud
 
G*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョンG*なクラウド 雲のかなたに ショートバージョン
G*なクラウド 雲のかなたに ショートバージョン
 
How To Build a Multi-Field Search Page For Your XPages Application
How To Build a Multi-Field Search Page For Your XPages ApplicationHow To Build a Multi-Field Search Page For Your XPages Application
How To Build a Multi-Field Search Page For Your XPages Application
 
Groovy Grails Gr8Ladies Women Techmakers: Minneapolis
Groovy Grails Gr8Ladies Women Techmakers: MinneapolisGroovy Grails Gr8Ladies Women Techmakers: Minneapolis
Groovy Grails Gr8Ladies Women Techmakers: Minneapolis
 
Spring boot 3g
Spring boot 3gSpring boot 3g
Spring boot 3g
 
Lambda Architecture using Google Cloud plus Apps
Lambda Architecture using Google Cloud plus AppsLambda Architecture using Google Cloud plus Apps
Lambda Architecture using Google Cloud plus Apps
 
Open Source - NOVALUG January 2019
Open Source  - NOVALUG January 2019Open Source  - NOVALUG January 2019
Open Source - NOVALUG January 2019
 
Supercharge your app with Cloud Functions for Firebase
Supercharge your app with Cloud Functions for FirebaseSupercharge your app with Cloud Functions for Firebase
Supercharge your app with Cloud Functions for Firebase
 
Plone pwns
Plone pwnsPlone pwns
Plone pwns
 
The Grails introduction workshop
The Grails introduction workshopThe Grails introduction workshop
The Grails introduction workshop
 
Fork cli tool
Fork cli toolFork cli tool
Fork cli tool
 
An open-source TIMES/MIRO app
An open-source TIMES/MIRO appAn open-source TIMES/MIRO app
An open-source TIMES/MIRO app
 
Grunt training deck
Grunt training deckGrunt training deck
Grunt training deck
 
Grails Plugins
Grails PluginsGrails Plugins
Grails Plugins
 
Grunt.js introduction
Grunt.js introductionGrunt.js introduction
Grunt.js introduction
 
Bluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part IBluemix hadoop beginners Guide part I
Bluemix hadoop beginners Guide part I
 
Automating Front-End Workflow
Automating Front-End WorkflowAutomating Front-End Workflow
Automating Front-End Workflow
 
Pyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web appsPyramid Lighter/Faster/Better web apps
Pyramid Lighter/Faster/Better web apps
 

Getting Groovy With Grails

  • 1. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 1 © Copyright 2010, Software Alchemy Getting Groovy with Grails Bryan Basham Software Alchemy basham47@gmail.com http://www.linkedin.com/in/SoftwareAlchemist Grails Architecture Getting Groovy w/ Grails Domain Modeling Getting Started
  • 2. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 2 © Copyright 2010, Software Alchemy Grails Architecture Domain Modeling Getting Groovy w/ Grails Install Grails Create App Create Entity GUI Scaffolding Basic Domain Modeling Getting Started Getting Started
  • 3. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 3 © Copyright 2010, Software Alchemy Install Grails ● Download Grails at http://www.grails.org/ – I am using version 1.3.4 for this tech talk ● Unpack ZIP file on computer ● Set GRAILS_HOME environment variable ● Add $GRAILS_HOME/bin to PATH
  • 4. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 4 © Copyright 2010, Software Alchemy Create a Grails App ● Execute command, eg: grails create-app MyApp
  • 5. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 5 © Copyright 2010, Software Alchemy MyApp Use Cases List employees Update employee Create employee Retrieve employee Delete employee Classic CRUD Operations
  • 6. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 6 © Copyright 2010, Software Alchemy Create a Domain Entity ● Create the Employee domain class, eg: grails create-domain-class com.example.Employee package com.example class Employee { String firstName String lastName Integer age static constraints = { } } «entity» Employee {from com.example} firstName : String lastName : String age : Integer
  • 7. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 7 © Copyright 2010, Software Alchemy Create a GUI Controller ● Create the Employee controller class, eg: grails create-controller com.example.Employee package com.example class EmployeeController { def scaffold = Employee } ● Grails scaffolding provides all basic CRUD operations and GUI Views
  • 8. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 8 © Copyright 2010, Software Alchemy Default GUI Scaffolding
  • 9. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 9 © Copyright 2010, Software Alchemy Default GUI Scaffolding (2)
  • 10. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 10 © Copyright 2010, Software Alchemy Default GUI Scaffolding (3)
  • 11. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 11 © Copyright 2010, Software Alchemy Behind the Looking Glass ● Create the Employee GUI controller class: grails generate-controller com.example.Employee class EmployeeController { def index = { redirect(action: "list", params: params) } def list = { params.max = Math.min(params.max ? params.int('max') : 10, 100) [employeeList: Employee.list(params), employeeTotal: Employee.count()] } def save = { def employee = new Employee(params) if (employee.save(flush: true)) { flash.message = "Employee ${employee.id} created." redirect(action: "show", id: employee.id) } else { render(view: "create", model: [employeeInstance: employee]) } }
  • 12. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 12 © Copyright 2010, Software Alchemy Behind the Looking Glass (2) ● Create the Employee GUI views: grails generate-views com.example.Employee
  • 13. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 13 © Copyright 2010, Software Alchemy Behind the Looking Glass (3) ● The list.gsp View: <table> <tbody> <g:each in="${employeeList}" status="i" var="employee"> <tr class="${(i % 2) == 0 ? 'odd' : 'even'}"> <td><g:link action="show" id="${employee.id}"> ${fieldValue(bean: employee, field: "id")}</g:link> </td> <td>${fieldValue(bean: employee, field: "age")}</td> <td>${fieldValue(bean: employee, field: "firstName")}</td> <td>${fieldValue(bean: employee, field: "lastName")}</td> </tr> </g:each> </tbody> </table>
  • 14. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 14 © Copyright 2010, Software Alchemy Behind the Looking Glass (4) ● The create.gsp View: <g:form action="save" > <table> <tbody> <tr class="prop"> <td valign="top" class="name"> <label for="age"><g:message code="employee.age.label" default="Age" /></label> </td> <td valign="top" class="value ${hasErrors(bean: employeeInstance, field: 'age', 'errors')}"> <g:textField name="age" value="${fieldValue(bean: employeeInstance, field: 'age')}" /> </td> </tr> ... </tbody> </table> </g:form>
  • 15. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 15 © Copyright 2010, Software Alchemy A Simple Relationship class Employee { String firstName String lastName Integer age Department department static constraints = { } } «entity» Department {from com.example} name : String «entity» Employee {from com.example} firstName : String lastName : String age : Integer department 10..* class Department { String name static constraints = { } }
  • 16. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 16 © Copyright 2010, Software Alchemy Create GUI components ● Create Department GUIs and recreate Employee GUIs A drop-down list of department objects, but the names are weird.
  • 17. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 17 © Copyright 2010, Software Alchemy Fix Department Display ● Add a simple toString method: class Department { String name String toString() { name } static constraints = { } } The toString method is used to create a useful display name. You could also create custom GSP code for the drop-down list widget.
  • 18. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 18 © Copyright 2010, Software Alchemy Grails Architecture Conv/Config Build tools Web techPlugins Groovy Getting Groovy w/ Grails Domain Modeling Install Grails Create App Create Entity GUI Scaffolding Basic Domain Modeling Getting Started Grails Architecture
  • 19. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 19 © Copyright 2010, Software Alchemy Grails Technology Stack The Java Virtual Machine Groovy Java Lang / JRE JDK Grails JavaEE Spring Hibernate SiteMesh Plugins... Your Grails Application
  • 20. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 20 © Copyright 2010, Software Alchemy Groovy Quick Look ● Groovy is a scripting langage on top of Java ● Syntax for lists and maps: – [1, 2, 3] – [foo:1, bar:2, baz:3] ● Closures: – [1, 2, 3].collect { it * it } => [1, 4, 9] ● Fancy Strings: – 'foo' is a Java String – “foo is ${map.foo}” is a GString
  • 21. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 21 © Copyright 2010, Software Alchemy Groovy Quick Look (2) ● Groovy classes are JavaBeans class Employee { String name Integer age } ● Setter/Getters are auto created unless specified: class Employee { String name Date dateOfBirth Integer getAge() { /* calc age from DoB */ } }
  • 22. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 22 © Copyright 2010, Software Alchemy Convention over Configuration ● Configuration is kept to a bare minimum ● Convention abounds: – Entities – Controllers and URL patterns – Services and dependency injection – Tag libraries – Scaffolding – and much more
  • 23. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 23 © Copyright 2010, Software Alchemy Logging ● Configure logging in grails-app/conf/ Config.groovy file: log4j = { root { info 'stdout' additivity = true } info 'com.example' // more configuration snipped } ● Log objects automatically available: if (employeeInstance.save(flush: true)) { log.info "Employee ${employeeInstance.id} created." redirect(action: "show", id: employeeInstance.id) }
  • 24. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 24 © Copyright 2010, Software Alchemy Data Sources ● Configured in the grails-app/conf/ DataSource.groovy file ● Database driver JAR file configured in the grails-app/conf/BuildConfig.groovy file ● Must create the database before using, but schema creation is handled by Grails – Use create-drop to create the DB on every run – This option destroys any data stored – Typically used during rapid prototyping
  • 25. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 25 © Copyright 2010, Software Alchemy Example: MySQL ● DataSource.groovy: environments { development { dataSource { dbCreate = "create-drop" // one of 'create', 'create- drop','update' url = "jdbc:mysql://localhost:8889/my-app-db" driverClassName = "com.mysql.jdbc.Driver" username = "root" password = "root" } } ● BuildConfig.groovy: dependencies { runtime 'mysql:mysql-connector-java:5.1.12' }
  • 26. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 26 © Copyright 2010, Software Alchemy Pre-populate DB ● Pre-populate the database using the grails- app/conf/BootStrap.groovy file: import com.example.Department; class BootStrap { def init = { servletContext -> if ( Department.count() == 0 ) { new Department(name:"Accounting").save() new Department(name:"Marketing").save() new Department(name:"Development").save() new Department(name:"Sales").save() } } def destroy = { } } The count() method is like the SQL statement: SELECT count(*) FROM department The save() method is like an SQL INSERT statement.
  • 27. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 27 © Copyright 2010, Software Alchemy Eclipse Integration ● Install the Groovy plugin: http://dist.springsource.org/release/GRECLIPSE/e3.6/ ● Groovy support in Eclipse is spotty but workable – Hard to find all necessary libraries – No obvious access to source or javadocs – Debugging Grails apps is very difficult ● Maven helps with some of these issues
  • 28. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 28 © Copyright 2010, Software Alchemy Maven Integration ● Creating a Grails app with Maven 2: mvn archetype:generate -DarchetypeGroupId=org.grails -DarchetypeArtifactId=grails-maven-archetype -DarchetypeVersion=1.3.4 -DgroupId=com.example -Dversion=0.1 -DartifactId=MyMavenApp cd MyMavenApp/ mvn initialize ● Supporting Eclipse: mvn -DdownloadSources=true -DdownloadJavadocs=true eclipse:eclipse
  • 29. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 29 © Copyright 2010, Software Alchemy Ant Integration ● You can use Grails scripts in an Ant script ● You can use Ant tasks in your own Grails scripts, Example: ant.property(file:"${basedir}/application.properties") def appName = "${Ant.project.properties['app.name']}" def appVersion = "${Ant.project.properties['app.version']}" def appPath = "${appName}-${appVersion}" target(main: "Create an archive of the complete project source.") { ant.zip(destfile: "../${appPath}-dist.zip") { zipfileset(dir:"${basedir}", prefix:"${appPath}") { exclude(name:"target/**") exclude(name:"web-app/WEB-INF/classes/**") } } } setDefaultTarget(main)
  • 30. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 30 © Copyright 2010, Software Alchemy External Deployment ● Build a WAR file using this command: grails dev war ● Deploy to your JavaEE compilant web container – WAR includes all Groovy and Grails JARs – WAR includes all infrastructure JARs – WAR includes DB driver JAR – WAR includes all plugins
  • 31. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 31 © Copyright 2010, Software Alchemy Web Technologies ● Controllers ● Views: GSPs ● Tag libraries ● Filters
  • 32. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 32 © Copyright 2010, Software Alchemy Controllers ● Controllers are Groovy classes that reside in the grails-app/controllers source directory ● Method names map to URL patterns, eg: http://localhost:8080/MyApp/employee/list – Maps to EmployeeController and list method ● View selection: – Use render to render a specific View component – Use redirect to tell the browser to redirect – Return a model Map to render this method's View, eg. list action renders list.gsp
  • 33. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 33 © Copyright 2010, Software Alchemy Views: GSPs ● Very much like JSPs but uses Groovy as the scripting language; cavet: don't script! ● Use custom tags for view logic – Large built-in library – Easy to create your own ● GSP attributes: – standard JSP attribute scopes plus flash scope – named values in the action method's model Map ● Grails uses SiteMesh for layout control
  • 34. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 34 © Copyright 2010, Software Alchemy Tag Libraries ● Tag libraries are Groovy classes that reside in the grails-app/taglib source directory ● Each method provides a custom tag, eg: class MyTags { def isAdmin = { attrs, body -> def user = attrs['user'] if ( user != null && checkUserPrivs(user) ) { out << body() } } } ● No configuration required ● Automatically available in all GSPs, eg: <g:isAdmin user=”${theUser}”>ADMIN CONTENT</g:isAdmin>
  • 35. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 35 © Copyright 2010, Software Alchemy Request Filters ● Filters are Groovy classes that reside in the grails-app/conf source directory that end in Filters class SecurityFilters { def filters = { loginCheck(controller:'*', action:'*') { before = { if (params.controller == null) { redirect(action:'login') return true } else if(!session.user && !actionName.equals('login')) { redirect(action:'login') return false } } } } }
  • 36. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 36 © Copyright 2010, Software Alchemy Transactions and Services ● Controller actions can be made transactional – Use Spring SessionFactory injection – Or use the withTransaction method ● Service components are a better solution – All classes that reside in the grails- app/services source directory – Use the def transactional = true for Spring transaction AOP wrapping – Inject the service into the controller: def storeService // auto-injects StoreService
  • 37. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 37 © Copyright 2010, Software Alchemy Plugins ● Grails is a framework built on plugins ● Default plugins: – Hibernate: the Grails ORM (aka GORM) – Tomcat: the Grails default runtime environment ● Hundreds of additional plugins – Security (40) – Services (117) – JavaScript frameworks (74) – many more...
  • 38. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 38 © Copyright 2010, Software Alchemy Spring Security Plugin ● Install the plugin: grails install-plugin spring-security-core ● Create the User and Role entities: grails s2-quickstart com.example.security User Role «javaPackage» com.example.security «entity» Role authority : String «entity» User username : String password : String enabled : boolean role 1 0..* «entity» UserRoleuser 1 /+authorities
  • 39. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 39 © Copyright 2010, Software Alchemy BootStrap Roles and Users import com.example.security.*; class BootStrap { def springSecurityService def init = { servletContext -> // Define user role's def hrRepRole = Role.findByAuthority('ROLE_HR_REP') ?: new Role(authority: 'ROLE_HR_REP').save(failOnError: true) def hrMgrRole = Role.findByAuthority('ROLE_HR_MANAGER') ?: new Role(authority: 'ROLE_HR_MANAGER').save(failOnError: true) def adminRole = Role.findByAuthority('ROLE_ADMIN') ?: new Role(authority: 'ROLE_ADMIN').save(failOnError: true) // a few users: def adminUser = User.findByUsername('admin') ?: new User( username: 'admin', password: springSecurityService.encodePassword('admin'), enabled: true).save(failOnError: true) if (!adminUser.authorities.contains(adminRole)) { UserRole.create adminUser, adminRole } // and so on } }
  • 40. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 40 © Copyright 2010, Software Alchemy Define Security Constraints ● Use annotations on controller actions, eg: import grails.plugins.springsecurity.Secured class DepartmentController { @Secured(['ROLE_HR_MANAGER', 'ROLE_HR_REP']) def list = { ... } @Secured(['ROLE_HR_MANAGER']) def create = { ... } @Secured(['ROLE_ADMIN']) def delete = { ... } } ● Or static URL rules in the Config.groovy file ● Or store the rules in the database
  • 41. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 41 © Copyright 2010, Software Alchemy Grails Architecture Conv/Config Build tools Web techPlugins Groovy Getting Groovy w/ Grails Install Grails Create App Create Entity GUI Scaffolding Basic Domain Modeling Getting Started Domain Modeling Relationships Validation Enumerated types Derived properties Embedded properties Inheritance Domain Modeling
  • 42. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 42 © Copyright 2010, Software Alchemy HrApp Use Cases View HR action history Employee Manager HR Rep HR Mgr View department staff Promote employee Issue pay raise for employee Confirm employee promotion Confirm employee pay raise Issue cost-of-living raise to department Hire employee Terminate employee Confirm employee hire Confirm employee termination Confirm department COL raise Create/update job roles
  • 43. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 43 © Copyright 2010, Software Alchemy Domain Model is King!
  • 44. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 44 © Copyright 2010, Software Alchemy Property Validations ● Property constraints are defined in the Domain model, eg: class Employee { // skipping property definitions static constraints = { firstName(nullable:false, blank:false, maxSize:32) lastName(nullable:false, blank:false, maxSize:64) dateOfBirth(nullable:true) homeAddress(nullable:false) homePhone(nullable:false) cellPhone(nullable:true) department(nullable:false) jobRole(nullable:true) salary(nullable:true, min:10000) proposedChange(nullable:true) // workflow properties user(nullable:false) status(nullable:false) }
  • 45. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 45 © Copyright 2010, Software Alchemy Basic Enumerated Types ● Grails supports Java-style enums, eg: class Employee { // other properties Status status enum Status { CREATED, HIRED, DISCIPLINARY_REVIEW, TERMINATED; static def getActiveStatuses = { return [HIRED, DISCIPLINARY_REVIEW] } } // more code } ● ...but the enum name is stored in the DB field which is a bit wasteful, so... «enumeratedType» Status +CREATED +HIRED +DISCIPLARY_REVIEW +TERMINATED «entity» Employee firstName : String lastName : String ... status : Status
  • 46. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 46 © Copyright 2010, Software Alchemy Enumerated Types with Ids ● You can define an id field in the enum, eg: class EmployeeAction { // other properties enum ActionType { HIRE('HI'), RAISE('RA'), COL_RAISE('CR'), PROMOTE('PO'), TERMINATE('TE'); final String id ActionType(String id) { this.id = id } } // more code } ● ...so now the DB field is a two-char value. «enumeratedType» Status +HIRE('HI') +RAISE('RA') +COL_RAISE('CR') +PROMOTE('PO') +TERMINATE('TE') id : String «entity» EmployeeAction type : ActionType employee : Employee newRole : JobRole ...
  • 47. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 47 © Copyright 2010, Software Alchemy Derived Properties ● Also know as transient properties, eg: class Employee { // Properties Date dateOfBirth // Derived properties Integer getAge() { // corner case if ( dateOfBirth == null ) return null; // calculate and memoize the employee's age _age = _age ?: DateUtils.dateDiffYears(new Date(), dateOfBirth) return _age } private Integer _age // GORM constraints static transients = [ 'age', ... ] } «entity» Employee dateOfBirth : Date /age : Integer ...
  • 48. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 48 © Copyright 2010, Software Alchemy Derived Relationships ● You can do the same with computed relationships, eg: class Employee { // Derived properties List<EmployeeAction> getHistory() { // calculate and memoize the employee's HR history _history = _history ?: EmployeeAction.findAllByEmployee( this, [sort:'proposedDate', order:'asc'] ) return _history } private List<EmployeeAction> _history // GORM constraints static transients = [ 'age', 'history', ... ] } «entity» EmployeeAction/history *«entity» Employee
  • 49. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 49 © Copyright 2010, Software Alchemy Embedded Properties ● Grails encourages rich object models even for non-Entity objects, eg: class Employee { // Properties Address homeAddress PhoneNumber homePhone PhoneNumber cellPhone // GORM constraints static embedded = [ 'homeAddress', 'homePhone', 'cellPhone' ] } class PhoneNumber { // Properties String areaCode String prefix String number // GORM constraints... } «entity» Employee homeAddress : Address homePhone : PhoneNumber cellPhone : PhoneNumber «valueObject» PhoneNumber areaCode : String prefix : String number : String
  • 50. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 50 © Copyright 2010, Software Alchemy Embedded Properties (2) ● GORM creates a DB schema with each field of the Value Object embedded in the fields of the Entity. class Employee { // Properties Address homeAddress PhoneNumber homePhone PhoneNumber cellPhone }
  • 51. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 51 © Copyright 2010, Software Alchemy Relationships ● Grails supports: one-to-one, one-to-many and many-to-many ● Grails supports uni- and bi-directional relationships ● Grails support ownership, with cascading deletes ● Grails supports unordered sets, sorted sets, and lists (with ordering index)
  • 52. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 52 © Copyright 2010, Software Alchemy One-to-One Relationships class Employee { // Properties Department department JobRole jobRole User user // GORM constraints static constraints = { department(nullable:false) jobRole(nullable:true) user(nullable:false) } «entity» JobRolejobRole 0..1 «entity» User {from com.example.security} user1 «entity» Employee user : User jobRole : JobRole department : Department «entity» Department department 1
  • 53. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 53 © Copyright 2010, Software Alchemy One-to-Many class HRRepresentative extends Employee { // Properties Set<Department> departments // GORM constraints static hasMany = [ 'departments' : Department ] } «entity» HRRepresentative departments : Set<Department> «entity» Department departments *
  • 54. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 54 © Copyright 2010, Software Alchemy Inheritance ● Inheritance is supported with little to no configuration ● By default, the whole hierarchy is stored in one table ● You can configure Grails to use multiple tables ● ...but be aware of the DB performance impact of multiple selects and table joins
  • 55. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 55 © Copyright 2010, Software Alchemy Inheritance (2) class Employee { ... } class HRRepresentative extends Employee { ... } class Manager extends Employee { ... } class Engineer extends Employee { ... } «entity» Employee «entity» HRRepresentative «entity» Manager «entity» Engineer
  • 56. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 56 © Copyright 2010, Software Alchemy Inheritance (3) ● The resulting DB table:
  • 57. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 57 © Copyright 2010, Software Alchemy Grails Architecture Conv/Config Build tools Web techPlugins Groovy Getting Groovy w/ Grails Install Grails Create App Create Entity GUI Scaffolding Basic Domain Modeling Getting Started Domain Modeling Relationships Validation Enumerated types Derived properties Embedded properties Inheritance Q & A
  • 58. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 58 © Copyright 2010, Software Alchemy Ten Great Topics Not Covered 1) Supports unit and integration testing 2) Supports RESTful URL patterns 3) Supports Java and Spring integration 4) Supports multiple environments 5) Integration to legacy DBs using Hibernate mappings 6) Supports turning Service components into Web Services 7) Easy to create your own plugins for cross-team sharing 8) Supports other continuous integration tools: Hudson, Ivy, etc 9) Supports data auditing and time stamping w/ GORM event model 10) Supports Ajax and Spring Web Flows
  • 59. Rochester JUG: 9-Nov-2010 Bryan Basham – Getting Groovy with Grails Slide 59 © Copyright 2010, Software Alchemy Resources ● Groovy (http://groovy.codehaus.org/) – Reference docs (click here) – Reference card (click here) ● Grails (http://www.grails.org/) – Reference docs (click here) ● Eclipse plugin (http://dist.springsource.org/release/GRECLIPSE/e3.6/) ● The Definitive Guide to Grails (by Rocher and Brown, Apress)