SlideShare a Scribd company logo
By: Saurabh Dixit
 Grails is a full stack framework and attempts
to solve as many pieces of the web
development puzzle through the core
technology and its associated plugins.
 Need not to worry about XML configuration
files
 Creating controller classes:
 Creating Services:
 Command Objects in grails:
 In Grails, command objects are like domain
classes, but don’t persist data.
 They are very useful when you need to
group request parameters in a single object.
 First thing you‘ll need to do is describe your
command object. It is fine to do in the same
file that contains controller that will use it.
 If command will be used by more than one
controller, describe it in controllers or in
groovy source directory.
 DeclaringCommand Objects:
▪ Command object classes are defined just like any other class.
@Validateable
class PasswordChangeCommand {
String username
String actualPassword
String newPassword
String repNewPassword
static constraints = {
newPassword(nullable: false, blank: false)
repNewPassword(nullable: false, blank: false, validator: {String
repNewPassword, obj ->
String newPassword = obj.properties['newPassword']
if( !(newPassword == repNewPassword) ) {
return 'PasswordChangeCommand.newPasswordMismatch' //key of the i18 message
} else {
return true
}
})
}
}
def checkRegisterCommand = { PasswordChangeCommand
command->
if ( command.validate() ) {
println("Command validated")
redirect action: 'index'
}
else {
println("Command validation failed")
flash.message = command.errors.allErrors.collect { error ->
error.field
}.join(", ")
redirect action: 'index'
}
}
<g:form action="checkRegisterCommand">
username: <g:textField name="username"/>
actualPassword: <g:textField name="actualPassword"/>
newPassword: <g:textField name="newPassword"/>
repNewPassword: <g:textField name="repNewPassword"/>
<g:submitButton name="checkRegisterCommand" />
</g:form>
 As this example shows, since the command
object class is marked withValidateable you
can define constraints in command objects
just like in domain classes.
 Another way to make a command object
class validateable is to define it in the same
source file as the controller which is using the
class as a command object.
 If a command object class is not defined in
the same source file as a controller which
uses the class as a command object and the
class is not marked withValidateable, the
class will not be made validateable.
 It is not required that command object
classes be validateable.
 Command objects can participate in dependency
injection.This is useful if your command object has some
custom validation logic which uses a Grails service:
@grails.validation.Validateable
class LoginCommand {
def loginService
String username
String password
static constraints = {
username validator: { val, obj ->
obj.loginService.canLogin(obj.username, obj.password)
}
}
}
 Sharing Constraints Between Classes:
 A common pattern in Grails is to use command
objects for validating user-submitted data and
then copy the properties of the command object
to the relevant domain classes.
 This often means that your command objects and
domain classes share properties and their
constraints.
 You could manually copy and paste the
constraints between the two, but that's a very
error-prone approach. Instead, make use of Grails'
global constraints and import mechanism.
 Global Constraints:
 In addition to defining constraints in domain
classes, command objects and other validateable
classes, you can also define them in grails-
app/conf/Config.groovy:
grails.gorm.default.constraints = {
'*'(nullable: true, size: 1..20)
myShared(nullable: false, blank: false)
}
 These constraints are not attached to any particular
classes, but they can be easily referenced from any
validateable class:
class User {
...
static constraints = {
login shared: "myShared"
}
}
 Note:
▪ the use of the shared argument, whose value is the name of one of the constraints
defined in grails.gorm.default.constraints.
▪ Despite the name of the configuration setting, you can reference these shared
constraints from any validateable class, such as command objects. The '*' constraint
is a special case: it means that the associated constraints ('nullable' and 'size' in the
above example) will be applied to all properties in all validateable classes. These
defaults can be overridden by the constraints declared in a validateable class.
 Importing Constraints:
 Grails 2 introduced an alternative approach to
sharing constraints that allows you to import a set
of constraints from one class into another.
 Let's say you have a domain class like so:
class User {
String firstName
String lastName
String passwordHash
static constraints = {
firstName blank: false, nullable: false
lastName blank: false, nullable: false
passwordHash blank: false, nullable: false
}
}
 You then want to create a command object,
UserCommand, that shares some of the
properties of the domain class and the
corresponding constraints.You can do this
with the importFrom() method:
class UserCommand {
String firstName
String lastName
String password
String confirmPassword
static constraints = {
importFrom User
password blank: false, nullable: false
confirmPassword blank: false, nullable: false
}
}
 This will import all the constraints from the User
domain class and apply them to UserCommand.
 The import will ignore any constraints in the source
class (User) that don't have corresponding properties
in the importing class (UserCommand).
 In the above example, only the 'firstName'
and 'lastName' constraints will be imported
into UserCommand because those are the
only properties shared by the two classes.
 If you want more control over which
constraints are imported, use the include and
exclude arguments.
 So for example, if you only wanted to import
the 'lastName' constraint you would use:
…
static constraints = {
importFrom User, include: ["lastName"]
…
}
 or if you wanted all constraints that ended with
'Name':
…
static constraints = {
importFrom User, include: [/.*Name/]
…
}
 Exploring scopes:
 You’ve seen how controller actions can return a
map that gets passed through to the view, and
you’ve seen the flash object also passing data
from controller to view.
 This passing of information, and the lifetime of
the variables that you pass, is known as variable
scope.
 Grails supports different scopes to store
information in, and each of them lasts a
different length of time.When you passed data
in a map from a controller to a view,
you were implicitly making use of request scope.
 But Grails lets you reference the different scopes
explicitly so you can store data for as long as you
need it.
 In particular, Grails offers you four special
map-like storage scopes that you can
reference by name in every controller action.
 Grails supports four storage contexts for
passing content between controllers and
forms Scope variable Survival time for entries
in this scope:
 request: Survive until the target GSP finishes
rendering flash: Survive to the next page, and
the one after that
 session: Survive until the current user closes
the browser
 servletContext: Survive until the application
is restarted (this map is shared by all users)
 REQUEST SCOPE:
▪ Request scope is great when you want to store data that is
shared only between your controller and the view (normally a
GSP page).
 FLASH SCOPE: Basically single redirect
▪ Entries in the flash map survive one (and only one) redirect,
after which they’re removed.
 SESSION SCOPE:
▪ The next longest lived scope is session scope. Objects that
you place in session scope remain until the user closes their
browser.
▪ Internally, servers use a session cookie called JSESSIONID to
map a user to their session, and the cookie expires when they
close their browser (or when the server times out the session
due to inactivity).
 Session gotchas:the mystery of the
detached object
 If you’re storing a domain object in the session
(such as the logged-in User object), the object will
become detached from your Hibernate session.
That means you won’t be able to access any
uninitialized lazy-loaded relationships the object
holds.
 For example, you won’t be able to call
session.user.following.each {}.
 To reattach the object (so you can walk its
object graph of relationships, for instance),
 use the attach() method that is available on
all domain classes.
 For our User example, it would look like this:
def user = session.user
if (!user.isAttached()) {
user.attach()
}
user.following.each { nextFollowing -> /* do stuff */ }
 SERVLETCONTEXT (APPLICATION) SCOPE:
 The final scope available is servletContext scope,
sometimes called application scope.
 This map is shared across your whole application, and
it’s handy for storing state that’s not dependent on
any particular user (such as the number of logins since
the application was started).
 Throughout the documentation so far the
convention used for URLs has been the
default of /controller/action/id.
 However, this convention is not hard wired
into Grails and is in fact controlled by a URL
Mappings class located at grailsapp/
conf/UrlMappings.groovy.
 The UrlMappings class contains a single
property called mappings that has been
assigned a block of code:
class UrlMappings {
static mappings = {
}
}
 Mapping to Controllers and Actions:
To create a simple mapping simply use a
relative URL as the method name and specify
named parameters for the controller and
action to map to:
"/product"(controller: "product", action: "list")
 In this case we've mapped the URL /product to
the list action of the ProductController. Omit the
action definition to map to the default action of
the controller:
"/product"(controller: "product")
 An alternative syntax is to assign the controller
and action to use within a block passed to the
method:
"/product" {
controller = "product"
action = "list"
}
 Which syntax you use is largely dependent on
personal preference.
 To rewrite one URI onto another explicit URI
(rather than a controller/action pair) do
something like this:
"/hello"(uri: "/hello.dispatch")
 Rewriting specific URIs is often useful when
integrating with other frameworks.
 SimpleVariables
 The previous section demonstrated how to map
simple URLs with concrete "tokens".
 In URL mapping speak tokens are the sequence of
characters between each slash, '/'.
 A concrete token is one which is well defined such
as as /product. However, in many circumstances
you don't know what the value of a particular
token will be until runtime.
 In this case you can use variable placeholders
within the URL for example:
static mappings = {
"/product/$id"(controller: "product")
}
 In this case by embedding a $id variable as
the second token Grails will automatically
map the second token into a parameter
(available via the params object) called id.
 For example given the URL /product/MacBook,
the following code will render "MacBook" to the
response:
class ProductController {
def index() { render params.id }
}
 In this case by embedding a $id variable as the
second token Grails will automatically map the
second token into a parameter (available via the
params object) called id.
 For example given the URL
/product/MacBook,
the following code will render "MacBook" to
the response:
class ProductController {
def index() { render params.id }
}
 You can of course construct more complexexamples
of mappings.
 For example the traditional blog URL format could
be mapped as follows:
static mappings = {
"/$blog/$year/$month/$day/$id"(controller: "blog", action: "show")
}
 The above mapping would let you do things like:
/graemerocher/2007/01/10/my_funky_blog_entry
 The individual tokens in the URL would again be
mapped into the params object with values
available for year, month, day, id and so on.
 OptionalVariables:
 Another characteristic of the default mapping is
the ability to append a ? at the end of a variable to
make it an optional token.
 In a further example this technique could be
applied to the blog URL mapping to have more
flexible linking:
static mappings = {
"/$blog/$year?/$month?/$day?/$id?"(controller:"blog",
action:"show")
}
 With this mapping all of these URLs would
match with only the relevant parameters
being populated in the params object:
/graemerocher/2007/01/10/my_funky_blog_entry
/graemerocher/2007/01/10
/graemerocher/2007/01
/graemerocher/2007
/graemerocher
 ArbitraryVariables:
You can also pass arbitrary parameters from the URL mapping
into the controller by just setting
them in the block passed to the mapping:
"/holiday/win" {
id = "Marrakech"
year = 2007
}
 This variables will be available within the
params object passed to the controller.
 You can resolve a URL to a view without a
controller or action involved.
For example to map the root URL / to a GSP
at the location grails-app/views/index.gsp
you could use:
static mappings = {
"/"(view: "/index") // map the root URL
}
 Alternatively if you need a view that is
specific to a given controller you could use:
static mappings = {
"/help"(controller: "site", view: "help") // to a view for a
controller
}
 Grails also lets you map HTTP response codes
to controllers, actions or views. Just use a
method name that matches the response
code you are interested in:
static mappings = {
"403"(controller: "errors", action: "forbidden")
"404"(controller: "errors", action: "notFound")
"500"(controller: "errors", action: "serverError")
}
 Or you can specify custom error pages:
static mappings = {
"403"(view: "/errors/forbidden")
"404"(view: "/errors/notFound")
"500"(view: "/errors/serverError")
}
 Declarative Error Handling:
 In addition you can configure handlers for individual
exceptions:
static mappings = {
"403"(view: "/errors/forbidden")
"404"(view: "/errors/notFound")
"500"(controller: "errors", action: "illegalArgument",
exception: IllegalArgumentException)
"500"(controller: "errors", action: "nullPointer",
exception: NullPointerException)
"500"(controller: "errors", action: "customException",
exception: MyException)
"500"(view: "/errors/serverError")
}
 With this configuration, an
IllegalArgumentException will be handled by the
illegalArgument action in ErrorsController,
 a NullPointerException will be handled by the
nullPointer action, and a MyException will be
handled by the customException action.
 Other exceptions will be handled by the catch-all
rule and use the
/errors/serverError view.
 You can access the exception from your custom error
handing view or controller action using the request's
exception attribute like so:
class ErrorController {
def handleError() {
def exception = request.exception
// perform desired processing to handle the exception
}
}
 If your error-handling controller action throws an
exception as well, you'll end up with a
StackOverflowException.
 Grails' URL mappings mechanism also supports
wildcard mappings. For example consider the
following mapping:
static mappings = {
"/images/*.jpg"(controller: "image")
}
 This mapping will match all paths to images
such as /image/logo.jpg.
 Of course you can achieve the same effect with a
variable:
static mappings = {
"/images/$name.jpg"(controller: "image")
}
 However, you can also use double wildcards
to match more than one level below:
static mappings = {
"/images/**.jpg"(controller: "image")
}
 In this cases the mapping will match
/image/logo.jpg as well as
/image/other/logo.jpg.
 Even better you can use a double wildcard
variable:
static mappings = {
// will match /image/logo.jpg and /image/other/logo.jpg
"/images/$name**.jpg"(controller: "image")
}
 In this case it will store the path matched by
the wildcard inside a name parameter
obtainable from the params object:
def name = params.name
println name // prints "logo" or "other/logo"
 URL Mappings also support named mappings, that is
mappings which have a name associated with them.
 The name may be used to refer to a specific mapping
when links are generated.
 The syntax for defining a named mapping is as
follows:
static mappings = {
name <mapping name>: <url pattern> {
// …
}
}
 For example:
static mappings = {
name personList: "/showPeople" {
controller = 'person'
action = 'list'
}
name accountDetails: "/details/$acctNumber" {
controller = 'product'
action = 'accountDetails'
}
}
 The mapping may be referenced in a link tag in a
GSP.
<g:link mapping="personList">List People</g:link>
 That would result in:
<a href="/showPeople">List People</a>
 Parameters may be specified using the params
attribute.
<g:link mapping="accountDetails“params="[acctNumber:'8675309']">
Show Account
</g:link>
 That would result in:
<a href="/details/8675309">ShowAccount</a>
 Alternatively you may reference a named
mapping using the link namespace.
<link:personList>List People</link:personList>
 That would result in:
<a href="/showPeople">List People</a>
 The link namespace approach allows
parameters to be specified as attributes.
<link:accountDetails acctNumber="8675309">Show Account</link:accountDetails>
 That would result in:
<a href="/details/8675309">ShowAccount</a>
 To specify attributes that should be applied to
the generated href, specify a Map value to
the attrs attribute.
 These attributes will be applied directly to the
href, not passed through to be used as
request parameters.
<link:accountDetails attrs="[class: 'fancy']" acctNumber="8675309">
ShowAccount
</link:accountDetails>
 That would result in:
<a href="/details/8675309" class="fancy">ShowAccount</a>
 Customizing URL Formats:
 The default URL Mapping mechanism supports
camel case names in the URLs.The default URL
for accessing an action named addNumbers in a
controller named MathHelperController would be
something like /mathHelper/addNumbers.
 Grails allows for the customization of this pattern
and provides an implementation which replaces
the camel case convention with a hyphenated
convention that would support URLs like /math-
helper/add-numbers.
 To enable hyphenated URLs assign a value of
"hyphenated" to the grails.web.url.converter
property in grails-app/conf/Config.groovy.
// grails-app/conf/Config.groovy
grails.web.url.converter = 'hyphenated'
 Namespaced Controllers:
 An application is not allowed to define multiple
controllers with the same name, even if they are
defined in separate packages.
 For example an application may not contain
com.accounting.ReportingController and
com.humanresources.ReportingController.
 However it is allowed for an application to use a
plugin which provides a controller with the same
name as a controller provided by the application
as long as the controllers are in separate
packages.
 For example, an application may include a
controller named
com.accounting.ReportingController
 and the application may use a plugin which
provides a controller named
com.humanresources.ReportingController.
 The only issue with that is the URL mapping for
the controller provided by the plugin needs to be
explicit in specifying that the mapping applies to
the ReportingController which is provided by the
plugin.
static mappings = {
"/accountingReports" {
controller = "reporting"
}
"/humanResourceReports" {
controller = "reporting"
plugin = "humanResources"
}
}
 With that mapping in place, a request to
/accountingReports will be handled by the
ReportingController which is defined in the
application.
 A request to /humanResourceReports will be
handled by the ReportingController which is
provided by the humanResources plugin
 There could be any number of
ReportingController controllers provided by
any number of plugins but no plugin may
provide more than one ReportingController
even if they are defined in separate packages.
 Assigning a value to the plugin variable in the
mapping is only required if there are multiple
controllers with the same name available at
runtime provided by the application and/or
plugins.
 If the humanResources plugin provides a
ReportingController and there is no other
ReportingController available at runtime, the
following mapping would work.
static mappings = {
"/humanResourceReports" {
controller = "reporting"
}
Grails basics

More Related Content

What's hot (20)

PDF
React, Redux, ES2015 by Max Petruck
Maksym Petruk
 
PPTX
Introduction to React JS for beginners
Varun Raj
 
PDF
Processing large-scale graphs with Google(TM) Pregel by MICHAEL HACKSTEIN at...
Big Data Spain
 
PPT
Executing Sql Commands
leminhvuong
 
PPTX
Database connect
Yoga Raja
 
PDF
Andrzej Ludwikowski - Event Sourcing - what could possibly go wrong? - Codemo...
Codemotion
 
PDF
React Lifecycle and Reconciliation
Zhihao Li
 
PDF
React Native: JS MVC Meetup #15
Rob Gietema
 
PPS
CS101- Introduction to Computing- Lecture 32
Bilal Ahmed
 
PPTX
Java Servlet
Yoga Raja
 
PPS
Java rmi example program with code
kamal kotecha
 
PPT
ASP.NET Session 11 12
Sisir Ghosh
 
PDF
Solid scala
Knoldus Inc.
 
PPTX
Redux training
dasersoft
 
PPTX
Chain of Responsibility Pattern
Hüseyin Ergin
 
PDF
Workshop 20: ReactJS Part II Flux Pattern & Redux
Visual Engineering
 
PDF
React Development with the MERN Stack
Troy Miles
 
ODP
GraniteDS 360|Flex DC
wdrai
 
PPT
Java jdbc
Arati Gadgil
 
PPTX
Introduction to RxJS
Abul Hasan
 
React, Redux, ES2015 by Max Petruck
Maksym Petruk
 
Introduction to React JS for beginners
Varun Raj
 
Processing large-scale graphs with Google(TM) Pregel by MICHAEL HACKSTEIN at...
Big Data Spain
 
Executing Sql Commands
leminhvuong
 
Database connect
Yoga Raja
 
Andrzej Ludwikowski - Event Sourcing - what could possibly go wrong? - Codemo...
Codemotion
 
React Lifecycle and Reconciliation
Zhihao Li
 
React Native: JS MVC Meetup #15
Rob Gietema
 
CS101- Introduction to Computing- Lecture 32
Bilal Ahmed
 
Java Servlet
Yoga Raja
 
Java rmi example program with code
kamal kotecha
 
ASP.NET Session 11 12
Sisir Ghosh
 
Solid scala
Knoldus Inc.
 
Redux training
dasersoft
 
Chain of Responsibility Pattern
Hüseyin Ergin
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Visual Engineering
 
React Development with the MERN Stack
Troy Miles
 
GraniteDS 360|Flex DC
wdrai
 
Java jdbc
Arati Gadgil
 
Introduction to RxJS
Abul Hasan
 

Similar to Grails basics (20)

PPTX
Grails basics part2
Saurabh Dixit
 
PPTX
Controller
Vijay Shukla
 
POT
intoduction to Grails Framework
Harshdeep Kaur
 
PDF
Grails Launchpad - From Ground Zero to Orbit
Zachary Klein
 
PPT
Introduction To Grails
Christopher Bartling
 
PPTX
Grails services
NexThoughts Technologies
 
PPTX
Command object
Vijay Shukla
 
PDF
Grails 101
David Jacobs
 
PPT
Grails Controllers
NexThoughts Technologies
 
PPTX
Grails Advanced
Saurabh Dixit
 
ODP
Command objects
NexThoughts Technologies
 
ODP
Groovygrailsnetbeans 12517452668498-phpapp03
Kevin Juma
 
ODP
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Sven Haiges
 
PPTX
Grails services
Vijay Shukla
 
PPTX
Grails Services
NexThoughts Technologies
 
ODP
Agile web development Groovy Grails with Netbeans
Carol McDonald
 
PPTX
Spring Northwest Usergroup Grails Presentation
ajevans
 
PPT
Grails Introduction - IJTC 2007
Guillaume Laforge
 
PDF
Grails patterns and practices
paulbowler
 
PPTX
Grails
ziyaaskerov
 
Grails basics part2
Saurabh Dixit
 
Controller
Vijay Shukla
 
intoduction to Grails Framework
Harshdeep Kaur
 
Grails Launchpad - From Ground Zero to Orbit
Zachary Klein
 
Introduction To Grails
Christopher Bartling
 
Grails services
NexThoughts Technologies
 
Command object
Vijay Shukla
 
Grails 101
David Jacobs
 
Grails Controllers
NexThoughts Technologies
 
Grails Advanced
Saurabh Dixit
 
Command objects
NexThoughts Technologies
 
Groovygrailsnetbeans 12517452668498-phpapp03
Kevin Juma
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Sven Haiges
 
Grails services
Vijay Shukla
 
Grails Services
NexThoughts Technologies
 
Agile web development Groovy Grails with Netbeans
Carol McDonald
 
Spring Northwest Usergroup Grails Presentation
ajevans
 
Grails Introduction - IJTC 2007
Guillaume Laforge
 
Grails patterns and practices
paulbowler
 
Grails
ziyaaskerov
 
Ad

Recently uploaded (20)

PPTX
Top Managed Service Providers in Los Angeles
Captain IT
 
PDF
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
PDF
Productivity Management Software | Workstatus
Lovely Baghel
 
PDF
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
PPTX
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
PDF
2025-07-15 EMEA Volledig Inzicht Dutch Webinar
ThousandEyes
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PPTX
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
PPTX
Earn Agentblazer Status with Slack Community Patna.pptx
SanjeetMishra29
 
PDF
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
PDF
Rethinking Security Operations - Modern SOC.pdf
Haris Chughtai
 
PDF
GITLAB-CICD_For_Professionals_KodeKloud.pdf
deepaktyagi0048
 
PDF
CIFDAQ'S Token Spotlight for 16th July 2025 - ALGORAND
CIFDAQ
 
PDF
UiPath vs Other Automation Tools Meeting Presentation.pdf
Tracy Dixon
 
PDF
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
PPTX
Lecture 5 - Agentic AI and model context protocol.pptx
Dr. LAM Yat-fai (林日辉)
 
PDF
How Current Advanced Cyber Threats Transform Business Operation
Eryk Budi Pratama
 
PDF
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
PDF
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
PDF
OpenInfra ID 2025 - Are Containers Dying? Rethinking Isolation with MicroVMs.pdf
Muhammad Yuga Nugraha
 
Top Managed Service Providers in Los Angeles
Captain IT
 
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
Productivity Management Software | Workstatus
Lovely Baghel
 
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
2025-07-15 EMEA Volledig Inzicht Dutch Webinar
ThousandEyes
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
Earn Agentblazer Status with Slack Community Patna.pptx
SanjeetMishra29
 
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
Rethinking Security Operations - Modern SOC.pdf
Haris Chughtai
 
GITLAB-CICD_For_Professionals_KodeKloud.pdf
deepaktyagi0048
 
CIFDAQ'S Token Spotlight for 16th July 2025 - ALGORAND
CIFDAQ
 
UiPath vs Other Automation Tools Meeting Presentation.pdf
Tracy Dixon
 
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
Lecture 5 - Agentic AI and model context protocol.pptx
Dr. LAM Yat-fai (林日辉)
 
How Current Advanced Cyber Threats Transform Business Operation
Eryk Budi Pratama
 
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
OpenInfra ID 2025 - Are Containers Dying? Rethinking Isolation with MicroVMs.pdf
Muhammad Yuga Nugraha
 
Ad

Grails basics

  • 2.  Grails is a full stack framework and attempts to solve as many pieces of the web development puzzle through the core technology and its associated plugins.  Need not to worry about XML configuration files
  • 5.  Command Objects in grails:  In Grails, command objects are like domain classes, but don’t persist data.  They are very useful when you need to group request parameters in a single object.
  • 6.  First thing you‘ll need to do is describe your command object. It is fine to do in the same file that contains controller that will use it.  If command will be used by more than one controller, describe it in controllers or in groovy source directory.
  • 7.  DeclaringCommand Objects: ▪ Command object classes are defined just like any other class. @Validateable class PasswordChangeCommand { String username String actualPassword String newPassword String repNewPassword static constraints = { newPassword(nullable: false, blank: false) repNewPassword(nullable: false, blank: false, validator: {String repNewPassword, obj -> String newPassword = obj.properties['newPassword'] if( !(newPassword == repNewPassword) ) { return 'PasswordChangeCommand.newPasswordMismatch' //key of the i18 message } else { return true } }) } }
  • 8. def checkRegisterCommand = { PasswordChangeCommand command-> if ( command.validate() ) { println("Command validated") redirect action: 'index' } else { println("Command validation failed") flash.message = command.errors.allErrors.collect { error -> error.field }.join(", ") redirect action: 'index' } }
  • 9. <g:form action="checkRegisterCommand"> username: <g:textField name="username"/> actualPassword: <g:textField name="actualPassword"/> newPassword: <g:textField name="newPassword"/> repNewPassword: <g:textField name="repNewPassword"/> <g:submitButton name="checkRegisterCommand" /> </g:form>
  • 10.  As this example shows, since the command object class is marked withValidateable you can define constraints in command objects just like in domain classes.  Another way to make a command object class validateable is to define it in the same source file as the controller which is using the class as a command object.
  • 11.  If a command object class is not defined in the same source file as a controller which uses the class as a command object and the class is not marked withValidateable, the class will not be made validateable.  It is not required that command object classes be validateable.
  • 12.  Command objects can participate in dependency injection.This is useful if your command object has some custom validation logic which uses a Grails service: @grails.validation.Validateable class LoginCommand { def loginService String username String password static constraints = { username validator: { val, obj -> obj.loginService.canLogin(obj.username, obj.password) } } }
  • 13.  Sharing Constraints Between Classes:  A common pattern in Grails is to use command objects for validating user-submitted data and then copy the properties of the command object to the relevant domain classes.  This often means that your command objects and domain classes share properties and their constraints.  You could manually copy and paste the constraints between the two, but that's a very error-prone approach. Instead, make use of Grails' global constraints and import mechanism.
  • 14.  Global Constraints:  In addition to defining constraints in domain classes, command objects and other validateable classes, you can also define them in grails- app/conf/Config.groovy: grails.gorm.default.constraints = { '*'(nullable: true, size: 1..20) myShared(nullable: false, blank: false) }
  • 15.  These constraints are not attached to any particular classes, but they can be easily referenced from any validateable class: class User { ... static constraints = { login shared: "myShared" } }  Note: ▪ the use of the shared argument, whose value is the name of one of the constraints defined in grails.gorm.default.constraints. ▪ Despite the name of the configuration setting, you can reference these shared constraints from any validateable class, such as command objects. The '*' constraint is a special case: it means that the associated constraints ('nullable' and 'size' in the above example) will be applied to all properties in all validateable classes. These defaults can be overridden by the constraints declared in a validateable class.
  • 16.  Importing Constraints:  Grails 2 introduced an alternative approach to sharing constraints that allows you to import a set of constraints from one class into another.  Let's say you have a domain class like so: class User { String firstName String lastName String passwordHash static constraints = { firstName blank: false, nullable: false lastName blank: false, nullable: false passwordHash blank: false, nullable: false } }
  • 17.  You then want to create a command object, UserCommand, that shares some of the properties of the domain class and the corresponding constraints.You can do this with the importFrom() method:
  • 18. class UserCommand { String firstName String lastName String password String confirmPassword static constraints = { importFrom User password blank: false, nullable: false confirmPassword blank: false, nullable: false } }  This will import all the constraints from the User domain class and apply them to UserCommand.  The import will ignore any constraints in the source class (User) that don't have corresponding properties in the importing class (UserCommand).
  • 19.  In the above example, only the 'firstName' and 'lastName' constraints will be imported into UserCommand because those are the only properties shared by the two classes.  If you want more control over which constraints are imported, use the include and exclude arguments.
  • 20.  So for example, if you only wanted to import the 'lastName' constraint you would use: … static constraints = { importFrom User, include: ["lastName"] … }  or if you wanted all constraints that ended with 'Name': … static constraints = { importFrom User, include: [/.*Name/] … }
  • 21.  Exploring scopes:  You’ve seen how controller actions can return a map that gets passed through to the view, and you’ve seen the flash object also passing data from controller to view.  This passing of information, and the lifetime of the variables that you pass, is known as variable scope.
  • 22.  Grails supports different scopes to store information in, and each of them lasts a different length of time.When you passed data in a map from a controller to a view, you were implicitly making use of request scope.  But Grails lets you reference the different scopes explicitly so you can store data for as long as you need it.
  • 23.  In particular, Grails offers you four special map-like storage scopes that you can reference by name in every controller action.  Grails supports four storage contexts for passing content between controllers and forms Scope variable Survival time for entries in this scope:
  • 24.  request: Survive until the target GSP finishes rendering flash: Survive to the next page, and the one after that  session: Survive until the current user closes the browser  servletContext: Survive until the application is restarted (this map is shared by all users)
  • 25.  REQUEST SCOPE: ▪ Request scope is great when you want to store data that is shared only between your controller and the view (normally a GSP page).  FLASH SCOPE: Basically single redirect ▪ Entries in the flash map survive one (and only one) redirect, after which they’re removed.  SESSION SCOPE: ▪ The next longest lived scope is session scope. Objects that you place in session scope remain until the user closes their browser. ▪ Internally, servers use a session cookie called JSESSIONID to map a user to their session, and the cookie expires when they close their browser (or when the server times out the session due to inactivity).
  • 26.  Session gotchas:the mystery of the detached object  If you’re storing a domain object in the session (such as the logged-in User object), the object will become detached from your Hibernate session. That means you won’t be able to access any uninitialized lazy-loaded relationships the object holds.
  • 27.  For example, you won’t be able to call session.user.following.each {}.  To reattach the object (so you can walk its object graph of relationships, for instance),  use the attach() method that is available on all domain classes.
  • 28.  For our User example, it would look like this: def user = session.user if (!user.isAttached()) { user.attach() } user.following.each { nextFollowing -> /* do stuff */ }  SERVLETCONTEXT (APPLICATION) SCOPE:  The final scope available is servletContext scope, sometimes called application scope.  This map is shared across your whole application, and it’s handy for storing state that’s not dependent on any particular user (such as the number of logins since the application was started).
  • 29.  Throughout the documentation so far the convention used for URLs has been the default of /controller/action/id.  However, this convention is not hard wired into Grails and is in fact controlled by a URL Mappings class located at grailsapp/ conf/UrlMappings.groovy.
  • 30.  The UrlMappings class contains a single property called mappings that has been assigned a block of code: class UrlMappings { static mappings = { } }
  • 31.  Mapping to Controllers and Actions: To create a simple mapping simply use a relative URL as the method name and specify named parameters for the controller and action to map to: "/product"(controller: "product", action: "list")
  • 32.  In this case we've mapped the URL /product to the list action of the ProductController. Omit the action definition to map to the default action of the controller: "/product"(controller: "product")  An alternative syntax is to assign the controller and action to use within a block passed to the method: "/product" { controller = "product" action = "list" }
  • 33.  Which syntax you use is largely dependent on personal preference.  To rewrite one URI onto another explicit URI (rather than a controller/action pair) do something like this: "/hello"(uri: "/hello.dispatch")  Rewriting specific URIs is often useful when integrating with other frameworks.
  • 34.  SimpleVariables  The previous section demonstrated how to map simple URLs with concrete "tokens".  In URL mapping speak tokens are the sequence of characters between each slash, '/'.  A concrete token is one which is well defined such as as /product. However, in many circumstances you don't know what the value of a particular token will be until runtime.
  • 35.  In this case you can use variable placeholders within the URL for example: static mappings = { "/product/$id"(controller: "product") }  In this case by embedding a $id variable as the second token Grails will automatically map the second token into a parameter (available via the params object) called id.
  • 36.  For example given the URL /product/MacBook, the following code will render "MacBook" to the response: class ProductController { def index() { render params.id } }  In this case by embedding a $id variable as the second token Grails will automatically map the second token into a parameter (available via the params object) called id.
  • 37.  For example given the URL /product/MacBook, the following code will render "MacBook" to the response: class ProductController { def index() { render params.id } }
  • 38.  You can of course construct more complexexamples of mappings.  For example the traditional blog URL format could be mapped as follows: static mappings = { "/$blog/$year/$month/$day/$id"(controller: "blog", action: "show") }  The above mapping would let you do things like: /graemerocher/2007/01/10/my_funky_blog_entry  The individual tokens in the URL would again be mapped into the params object with values available for year, month, day, id and so on.
  • 39.  OptionalVariables:  Another characteristic of the default mapping is the ability to append a ? at the end of a variable to make it an optional token.  In a further example this technique could be applied to the blog URL mapping to have more flexible linking: static mappings = { "/$blog/$year?/$month?/$day?/$id?"(controller:"blog", action:"show") }
  • 40.  With this mapping all of these URLs would match with only the relevant parameters being populated in the params object: /graemerocher/2007/01/10/my_funky_blog_entry /graemerocher/2007/01/10 /graemerocher/2007/01 /graemerocher/2007 /graemerocher
  • 41.  ArbitraryVariables: You can also pass arbitrary parameters from the URL mapping into the controller by just setting them in the block passed to the mapping: "/holiday/win" { id = "Marrakech" year = 2007 }  This variables will be available within the params object passed to the controller.
  • 42.  You can resolve a URL to a view without a controller or action involved. For example to map the root URL / to a GSP at the location grails-app/views/index.gsp you could use: static mappings = { "/"(view: "/index") // map the root URL }
  • 43.  Alternatively if you need a view that is specific to a given controller you could use: static mappings = { "/help"(controller: "site", view: "help") // to a view for a controller }
  • 44.  Grails also lets you map HTTP response codes to controllers, actions or views. Just use a method name that matches the response code you are interested in: static mappings = { "403"(controller: "errors", action: "forbidden") "404"(controller: "errors", action: "notFound") "500"(controller: "errors", action: "serverError") }
  • 45.  Or you can specify custom error pages: static mappings = { "403"(view: "/errors/forbidden") "404"(view: "/errors/notFound") "500"(view: "/errors/serverError") }
  • 46.  Declarative Error Handling:  In addition you can configure handlers for individual exceptions: static mappings = { "403"(view: "/errors/forbidden") "404"(view: "/errors/notFound") "500"(controller: "errors", action: "illegalArgument", exception: IllegalArgumentException) "500"(controller: "errors", action: "nullPointer", exception: NullPointerException) "500"(controller: "errors", action: "customException", exception: MyException) "500"(view: "/errors/serverError") }
  • 47.  With this configuration, an IllegalArgumentException will be handled by the illegalArgument action in ErrorsController,  a NullPointerException will be handled by the nullPointer action, and a MyException will be handled by the customException action.  Other exceptions will be handled by the catch-all rule and use the /errors/serverError view.
  • 48.  You can access the exception from your custom error handing view or controller action using the request's exception attribute like so: class ErrorController { def handleError() { def exception = request.exception // perform desired processing to handle the exception } }  If your error-handling controller action throws an exception as well, you'll end up with a StackOverflowException.
  • 49.  Grails' URL mappings mechanism also supports wildcard mappings. For example consider the following mapping: static mappings = { "/images/*.jpg"(controller: "image") }  This mapping will match all paths to images such as /image/logo.jpg.  Of course you can achieve the same effect with a variable: static mappings = { "/images/$name.jpg"(controller: "image") }
  • 50.  However, you can also use double wildcards to match more than one level below: static mappings = { "/images/**.jpg"(controller: "image") }  In this cases the mapping will match /image/logo.jpg as well as /image/other/logo.jpg.
  • 51.  Even better you can use a double wildcard variable: static mappings = { // will match /image/logo.jpg and /image/other/logo.jpg "/images/$name**.jpg"(controller: "image") }  In this case it will store the path matched by the wildcard inside a name parameter obtainable from the params object: def name = params.name println name // prints "logo" or "other/logo"
  • 52.  URL Mappings also support named mappings, that is mappings which have a name associated with them.  The name may be used to refer to a specific mapping when links are generated.  The syntax for defining a named mapping is as follows: static mappings = { name <mapping name>: <url pattern> { // … } }
  • 53.  For example: static mappings = { name personList: "/showPeople" { controller = 'person' action = 'list' } name accountDetails: "/details/$acctNumber" { controller = 'product' action = 'accountDetails' } }
  • 54.  The mapping may be referenced in a link tag in a GSP. <g:link mapping="personList">List People</g:link>  That would result in: <a href="/showPeople">List People</a>  Parameters may be specified using the params attribute. <g:link mapping="accountDetails“params="[acctNumber:'8675309']"> Show Account </g:link>
  • 55.  That would result in: <a href="/details/8675309">ShowAccount</a>  Alternatively you may reference a named mapping using the link namespace. <link:personList>List People</link:personList>  That would result in: <a href="/showPeople">List People</a>  The link namespace approach allows parameters to be specified as attributes. <link:accountDetails acctNumber="8675309">Show Account</link:accountDetails>
  • 56.  That would result in: <a href="/details/8675309">ShowAccount</a>  To specify attributes that should be applied to the generated href, specify a Map value to the attrs attribute.
  • 57.  These attributes will be applied directly to the href, not passed through to be used as request parameters. <link:accountDetails attrs="[class: 'fancy']" acctNumber="8675309"> ShowAccount </link:accountDetails>  That would result in: <a href="/details/8675309" class="fancy">ShowAccount</a>
  • 58.  Customizing URL Formats:  The default URL Mapping mechanism supports camel case names in the URLs.The default URL for accessing an action named addNumbers in a controller named MathHelperController would be something like /mathHelper/addNumbers.  Grails allows for the customization of this pattern and provides an implementation which replaces the camel case convention with a hyphenated convention that would support URLs like /math- helper/add-numbers.
  • 59.  To enable hyphenated URLs assign a value of "hyphenated" to the grails.web.url.converter property in grails-app/conf/Config.groovy. // grails-app/conf/Config.groovy grails.web.url.converter = 'hyphenated'
  • 60.  Namespaced Controllers:  An application is not allowed to define multiple controllers with the same name, even if they are defined in separate packages.  For example an application may not contain com.accounting.ReportingController and com.humanresources.ReportingController.
  • 61.  However it is allowed for an application to use a plugin which provides a controller with the same name as a controller provided by the application as long as the controllers are in separate packages.  For example, an application may include a controller named com.accounting.ReportingController  and the application may use a plugin which provides a controller named com.humanresources.ReportingController.
  • 62.  The only issue with that is the URL mapping for the controller provided by the plugin needs to be explicit in specifying that the mapping applies to the ReportingController which is provided by the plugin. static mappings = { "/accountingReports" { controller = "reporting" } "/humanResourceReports" { controller = "reporting" plugin = "humanResources" } }
  • 63.  With that mapping in place, a request to /accountingReports will be handled by the ReportingController which is defined in the application.  A request to /humanResourceReports will be handled by the ReportingController which is provided by the humanResources plugin
  • 64.  There could be any number of ReportingController controllers provided by any number of plugins but no plugin may provide more than one ReportingController even if they are defined in separate packages.  Assigning a value to the plugin variable in the mapping is only required if there are multiple controllers with the same name available at runtime provided by the application and/or plugins.
  • 65.  If the humanResources plugin provides a ReportingController and there is no other ReportingController available at runtime, the following mapping would work. static mappings = { "/humanResourceReports" { controller = "reporting" }