Controllers
Type Conversion on Parameters
With Grails we get a lot of extra support for handling request parameters. We can convert a request parameter value to a specific type with a simple method invocation. Grails adds for example the method int() to the parameter so we can return the request parameter value converted to an int. Grails adds several methods like byte(), long(), boolean() we can use in our code. And since Grails 2.0 also support for dates.
Update: it is also possible to get the values from request parameters with the same name.
class SimpleController {
def submit = {
def intValue = params.int('paramInt')
def shortValue = params.short('paramShort')
def byteValue = params.byte('paramByte')
def longValue = params.long('paramLong')
def doubleValue = params.double('paramDouble')
def floatValue = params.float('paramFloat')
def booleanValue = params.boolean('paramBoolean')
[ intValue: intValue, shortValue: shortValue,
byteValue: byteValue,
longValue: longValue, doubleValue: doubleValue,
floatValue: floatValue, booleanValue: booleanValue ]
}
}
We can run the following testcase to test the various parameter types and values.
import grails.test.*
class SimpleControllerTests extends ControllerUnitTestCase {
void testParams() {
controller.params.paramInt = '42'
controller.params.paramShort = '128'
controller.params.paramByte = '8'
controller.params.paramLong = '90192'
controller.params.paramDouble = '12.3'
controller.params.paramFloat = '901.22'
controller.params.paramBoolean = 'true'
def result = controller.submit()
assertEquals 42, result.intValue
assertEquals 128, result.shortValue
assertEquals 8, result.byteValue
assertEquals 90192L, result.longValue
assertEquals 12.3, result.doubleValue
assertEquals 901.22f, result.floatValue
assertTrue result.booleanValue
}
void testInvalidParams() {
controller.params.paramInt = 'test'
def result = controller.submit()
assertNull result.intValue
}
void testBooleanParam() {
controller.params.paramBoolean = 'false'
def result = controller.submit()
assertFalse result.booleanValue
}
}
Code written with Grails 1.2.
Original blog post written on February 22, 2010.
Get Values from Parameters with Same Name
Grails supports type conversion on request parameters. But it is also easy to handle multiple request parameters with the same name in Grails. We use the list() method on the params and we are sure we get back a list with values. Even if only one parameter with the given name is returned we get back a list.
// File: grails-app/controllers/SimpleController.groovy
class SimpleController {
def test = {
// Handles a query like 'http://localhost:8080/simple?role=admin&role=user'
def roles = params.list('role')
render roles.join(',') // Returns admin,user
}
}
Code written with Grails 1.2.
Original blog post written on March 10, 2010.
Get Request Parameters with Default Values
In Grails we can convert a request parameter to a type directly. We must then use the int(), short(), byte(), long(), double(), float(), boolean() or list() methods that are added to the params object available in our controllers.
Since Grails 2.3 we can also pass a default value, which is used when the request parameter is not set. In the following controller we use the double() method and define a default value of 42.0.
// File: grails-app/controllers/com/mrhaki/grails/SampleController.groovy
package com.mrhaki.grails
class SampleController {
def index() {
// Get request parameter named v.
// Use default value 42.0 if not set.
final double value = params.double('v', 42.0)
[value: value]
}
}
The following test shows that the default value is returned if the request parameter is not set, otherwise the value of the request parameter is returned:
// File: test/unit/com/mrhaki/grails/SampleControllerSpec.groovy
package com.mrhaki.grails
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SampleController)
class SampleControllerSpec extends Specification {
def "request parameter v must return default value if not set"() {
expect:
controller.index().value == 42.0
}
def "request parameter v must return value set"() {
given:
params.v = '10.1'
expect:
controller.index().value == 10.1
}
}
We can use the same methods now also to get attribute values in a tag library. So we can do a type conversion and provide a default value if we want to. In the following tag library we use this in the tag sample:
// File: grails-app/taglib/com/mrhaki/grails/SampleTagLib.groovy
package com.mrhaki.grails
class SampleTagLib {
static namespace = 'sample'
static returnObjectForTags = ['sample']
def sample = { attributes, body ->
final double value = attributes.double('v', 42.0)
value
}
}
With the following Spock specification we can see that the default value 42.0 is used if the attribute v is not set. Otherwise the value of the attribute is returned:
// File: test/unit/com/mrhaki/grails/SampleTagLibSpec.groovy
package com.mrhaki.grails
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SampleTagLib)
class SampleTagLibSpec extends Specification {
def "attribute v returns default value if attribute is not set"() {
expect:
applyTemplate('<sample:sample/>') == '42.0'
}
def "attribute v returns value if attribute v if set"() {
expect:
applyTemplate('<sample:sample v="${v}"/>', [v: 10.1]) == '10.1'
}
}
Code written with Grails 2.3.
Original blog post written on November 19, 2013.
Date Request Parameter Value Conversions
Grails has great support for type conversion on request parameters. And since Grails 2.0 the support has been extended to include dates. In our controller we can use the date() method on the params object to get a date value. The value of a request parameter is a String, so the String value is parsed to a Date object.
The default expected date format is yyyy-MM-dd HH:mm:ss.S. If we don’t specify a specific date format in the date() method then this format is used. Or we can add a format to our messages.properties with the key date.<param-name>.format. Grails will first try the default format, but if the request parameter cannot be parsed to a valid Date object then Grails will do a lookup of the date format in messages.properties. Technically Grails uses the MessageSource bean to get the format, so we even can define the format per language or country.
Alternatively we can pass a date format or multiple date formats to the date() method. Grails will use these date formats to parse the request parameter into a valid Date object.
Let’s show the different options we have in a simple sample controller:
// File: grails-app/controllers/param/date/SampleController.groovy
package param.date
class SampleController {
final def dateFormats = ['yyyy-MM-dd', 'yyyyMMdd']
def index() {
[
defaultFormatDate: defaultFormatDate,
defaultFormatNameDate: defaultFormatNameDate,
singleFormatDate: singleFormatDate,
multipleFormatsDate1: multipleFormatsDate1,
multipleFormatsDate2: multipleFormatsDate2
]
}
private Date getDefaultFormatDate() {
// Use default format yyyy-MM-dd HH:mm:ss.S
params.date 'defaultFormatDate'
}
private Date getDefaultFormatNameDate() {
// Lookup format with key date.defaultFormatNameDate.format
// in messages.properties: yyyy-MM-dd
params.date 'defaultFormatNameDate'
}
private Date getSingleFormatDate() {
params.date 'singleFormatDate', 'yyyyMMdd'
}
private Date getMultipleFormatsDate1() {
params.date 'multipleFormatsDate1', dateFormats
}
private Date getMultipleFormatsDate2() {
params.date 'multipleFormatsDate2', dateFormats
}
}
In messages.properties we define the format for the request parameter defaultFormatNameDate:
# File: grails-app/i18n/messages.properties
...
date.defaultFormatNameDate.format=yyyy-MM-dd
...
To show that the date parsing works we write a little integration test. We need this to be an integration test, because then the lookup of the key via the MessageSource bean works.
package param.date
import org.junit.Test
class SampleControllerTests extends GroovyTestCase {
@Test
void testDateParameters() {
def controller = new SampleController()
// Set request parameters.
def params = [
defaultFormatDate: inputDateTime.format('yyyy-MM-dd HH:mm:ss.S'),
defaultFormatNameDate: inputDateTime.format('yyyy-MM-dd'),
singleFormatDate: inputDateTime.format('yyyyMMdd'),
multipleFormatsDate1: inputDateTime.format('yyyy-MM-dd'),
multipleFormatsDate2: inputDateTime.format('yyyyMMdd')
]
controller.request.parameters = params
def model = controller.index()
assertDates inputDateTime, model.defaultFormatDate
assertDates inputDate, model.defaultFormatNameDate
assertDates inputDate, model.singleFormatDate
assertDates inputDate, model.multipleFormatsDate1
assertDates inputDate, model.multipleFormatsDate2
}
private void assertDates(final Date expected, final Date controllerDate) {
assertEquals expected.toGMTString(), controllerDate.toGMTString()
}
/**
* Create Date object for January 10, 2012 14:12:01.120
*/
private Date getInputDateTime() {
final Calendar cal = Calendar.instance
cal.updated(year: 2012, month: Calendar.JANUARY, date: 10,
hours: 14, minutes: 12, seconds: 1, milliSeconds: 120)
cal.time
}
private Date getInputDate() {
final Date inputDateTime = inputDateTime
inputDateTime.clearTime()
inputDateTime
}
}
Code written with Grails 2.0.
Original blog post written on January 11, 2012.
Binding Method Arguments in Controller Methods
Since Grails 2.0 we can use methods instead of closures to define actions for our controllers. We already could pass a command object to a method as argument, but we can also use primitive typed arguments in our method definition. The name of the argument is the name of the request parameter we pass to the controller. Grails will automatically convert the request parameter to the type we have used in our method definition. If the type conversion fails then the parameter will be null.
Let’s create a method in a controller with three arguments: a String typed argument with the names author and book. And an argument with type Long with the name id.
// File: grails-app/controllers/sample/MethodSampleController.groovy
package sample
class MethodSampleController {
/**
* Sample method with 3 arguments.
*
* @param author Name of author
* @param id Identifier for author
* @param book Book title
*/
def sample(final String author, final Long id, final String book) {
render "Params: author = $author, book= $book, id = $id"
}
}
If we invoke our controller with serverUrl/sample?id=100&book=It&author=Stephen%20King we get the following output:
Params: name= Stephen King, book = It, id = 100
Suppose we don’t provide a valid long value for the id parameter we see in the output id is null. We use the following URL serverUrl/sample?id=1a&book=The%20Stand&author=Stephen%20King.
Params: author = Stephen King, book = The Stand, id = null
After reading this blog post and looking at the Grails documentation I learned we can even change the name of the argument and map it to a request parameter name with the @RequestParameter annotation. So then the name of the argument and the request parameter don’t have to be the same.
Let’s change our sample method and see what the output is:
// File: grails-app/controllers/sample/MethodSampleController.groovy
package sample
import grails.web.RequestParameter
class MethodSampleController {
/**
* Sample method with 3 arguments.
*
* @param author Name of author
* @param id Identifier for author
* @param book Book title
*/
def sample(final String author,
@RequestParameter('identifier') final Long id,
@RequestParameter('bookTitle') final String book) {
render "Params: author = $author, book = $book, id = $id"
}
}
Now we need the following URL to see correct output: serverUrl/sample?bookTitle=It&identifier=200&author=Stephen%20King.
Params: name= Stephen King, book = It, id = 200
Code written with Grails 2.0.
Original blog post written on February 27, 2012.
Controller Properties as Model
To pass data from a controller to a view we must return a model. The model is a map with all the values we want to show on the Groovy Server Page (GSP). We can explicitly return a model from an action, but if we don’t do that the controller’s properties are passed as the model to the view. Remember that in Grails a new controller instance is created for each request. So it is save to use the properties of the controller as model in our views.
// File: grails-app/controllers/com/mrhaki/SampleController.groovy
package com.mrhaki
class SampleController {
def values = ['Grails', 'Groovy', 'Griffon', 'Gradle', 'Spock']
def greeting
def index = {
greeting = 'Welcome to My Blog'
// Don't return a model, so the properties become the model.
}
}
<%-- File: grails-app/views/sample/index.gsp --%>
<html>
<head>
</head>
<body>
<h1>${greeting}</h1>
<g:join in="${values}"/> rock!
</body>
</html>
Code written with Grails 1.3.7.
Original blog post written on February 25, 2011.
Using the header Method to Set Response Headers
Grails adds a couple of methods and properties to our controller classes automatically. One of the methods is the header() method. With this method we can set a response header with a name and value. The methods accepts two arguments: the first argument is the header name and the second argument is the header value.
In the following controller we invoke the header() method to set the header X-Powered-By with the Grails and Groovy version.
// File: grails-app/controller/header/ctrl/SampleController.groovy
package header.ctrl
class SampleController {
def grailsApplication
def index() {
final String grailsVersion = grailsApplication.metadata.getGrailsVersion()
final String groovyVersion = GroovySystem.version
header 'X-Powered-By', "Grails: $grailsVersion, Groovy: $groovyVersion"
}
}
We can test this with the following Spock specification:
// File: test/unit/header/ctrl/SampleControllerSpec.groovy
package header.ctrl
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(SampleController)
class SampleControllerSpec extends Specification {
def "index must set response header X-Powered-By with value"() {
when:
controller.index()
then:
response.headerNames.contains 'X-Powered-By'
response.header('X-Powered-By') == 'Grails: 2.2.4, Groovy: 2.0.8'
}
}
Code written with Grails 2.2.4
Original blog post written on August 14, 2013.
Render Binary Output with the File Attribute
Since Grails 2 we can render binary output with the render() method and the file attribute. The file attribute can be assigned a byte[], File, InputStream or String value. Grails will try to determine the content type for files, but we can also use the contentType attribute to set the content type.
In the following controller we find an image in our application using grailsResourceLocator. Then we use the render() method and the file and contenType attributes to render the image in a browser:
package com.mrhaki.render
import org.codehaus.groovy.grails.core.io.ResourceLocator
import org.springframework.core.io.Resource
class ImageController {
ResourceLocator grailsResourceLocator
def index() {
final Resource image =
grailsResourceLocator.findResourceForURI('/images/grails_logo.png')
render file: image.inputStream, contentType: 'image/png'
}
}
The following screenshots shows the output of the index() action in a web browser:
We can use the fileName attribute to set a filename for the binary content. This will also set a response header with the name Content-Disposition with a the filename as value. Most browser will then automatically download the binary content, so it can be saved on disk. Grails will try to find the content type based on the extension of the filename. A map of extensions and content type values is defined in the grails-app/conf/Config.groovy configuration file. We can add for example for png a new key/value pair:
...
grails.mime.types = [
all: '*/*',
png: 'image/png',
atom: 'application/atom+xml',
css: 'text/css',
csv: 'text/csv',
form: 'application/x-www-form-urlencoded',
html: ['text/html','application/xhtml+xml'],
js: 'text/javascript',
json: ['application/json', 'text/json'],
multipartForm: 'multipart/form-data',
rss: 'application/rss+xml',
text: 'text/plain',
xml: ['text/xml', 'application/xml']
]
...
In our controller we can change the code so we use the fileName attribute:
package com.mrhaki.render
import org.codehaus.groovy.grails.core.io.ResourceLocator
import org.springframework.core.io.Resource
class ImageController {
ResourceLocator grailsResourceLocator
def index() {
final Resource image =
grailsResourceLocator.findResourceForURI('/images/grails_logo.png')
render file: image.inputStream, fileName: 'logo.png'
}
}
Code written with Grails 2.2.4
Original blog post written on September 05, 2013.
Exception Methods in Controllers
Since Grails 2.3 we can define exception methods in our controllers to handle exceptions raised by code invoked in the action methods of the controllers. Normally we would write a try/catch statement to handle an exception or let it continue up the stack until a 500 error page is shown. But with exception methods we can write code to handle exceptions in a controller without a try/catch statement. An exception method should define the type of exception it handles as the method argument. We can have multiple exception methods for different exception types. Also subclasses of a controller will use the exception methods if applicable.
In the following controller we have a couple of action methods: index and show. And we have two exception methods: connectException and notFoundException. The connectException method has a single argument of type ConnectException. This means that any code in the controller that will raise a ConnectException will be handled by this method. And any ResourceNotFoundException thrown in the controller will be handled by the notFoundException method, because the argument type is ResourceNotFoundException.
package com.mrhaki.grails
class SampleController {
/**
* Service with methods that are invoked
* from the controller action methods.
*/
ExternalService externalService
//--------------------------------------------
// Action methods:
//--------------------------------------------
/** Index action method */
def index() {
// These method calls could throw a ConnectException.
// If the ConnectException occurs then the
// connectException(ConnectException) method is
// invoked and that method will handle the
// request further.
final all = externalService.all(params)
final total = externalService.count()
[items: all, totalCount: total]
}
/** Show action method */
def show(final Long id) {
// This method can throw a ConnectException
// or ResourceNotFoundException.
// If the ResourceNotFoundException is thrown
// the request is further handled by
// the notFoundException(ResourceNotFoundException)
// method.
final item = externalService.get(id)
[item: item]
}
//--------------------------------------------
// Exception methods:
//--------------------------------------------
/**
* If any method in this controller invokes code that
* will throw a ConnectException then this method
* is invoked.
*/
def connectException(final ConnectException exception) {
logException exception
render view: 'error', model: [exception: exception]
}
/**
* If any method in this controller invokes code that
* will throw a ResourceNotFoundException then this method
* is invoked.
*/
def notFoundException(final ResourceNotFoundException exception) {
logException exception
render view: 'notFound', model: [id: params.id, exception: exception]
}
/** Log exception */
private void logException(final Exception exception) {
log.error "Exception occurred. ${exception?.message}", exception
}
}
Code written with Grails 2.4.0.
Original blog post written on May 23, 2014.
Namespace Support for Controllers
In a Grails application we can organize our controllers into packages, but if we use the same name for multiple controllers, placed in different packages, then Grails cannot resolve the correct controller name. Grails ignores the package name when finding a controller by name. But with namespace support since Grails 2.3 we can have controllers with the same name, but we can use a namespace property to distinguish between the different controllers.
We can add a new static property to a controller class with the name namespace. The value of this property defines the namespace. We can then write new URL mappings in the grails-app/conf/UrlMappings.groovy file and use the namespace value as a mapping attribute.
Suppose we have two ReportController classes in our application. One is defined in package com.mrhaki.grails.user and the other in com.mrhaki.grails.common. The following code samples show sample implementations for both controllers:
// File: grails-app/controllers/com/mrhaki/grails/user/ReportController.groovy
package com.mrhaki.grails.user
class ReportController {
/** Namespace is set to user. Used in URLMappings. */
static namespace = 'user'
def index() {
render 'UserReport'
}
}
And the second controller:
// File: grails-app/controllers/com/mrhaki/grails/common/ReportController.groovy
package com.mrhaki.grails.common
class ReportController {
/** Namespace is set to common. Used in URLMappings. */
static namespace = 'common'
def index() {
render 'CommonReport'
}
}
In our UrlMappings.groovy file we can now add two extra mappings for these controllers and we use the new namespace attribute to point the mapping to the correct controller implementation.
// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {
static mappings = {
// Define mapping to com.mrhaki.grails.user.ReportController
// with namespace user.
"/user-report/$action?/$id?(.${format})?"(controller: 'report',
namespace: 'user')
// Define mapping to com.mrhaki.grails.common.ReportController
// with namespace common.
"/common-report/$action?/$id?(.${format})?"(controller: 'report',
namespace: 'common')
// Other mappings.
"/$controller/$action?/$id?(.${format})?"()
"/"(view: "/index")
"500"(view: '/error')
}
}
The namespace support is also useful in building RESTful APIs with Grails. We can use the namespace attribute to have different versions for the same controller. For example in the following UrlMappings.groovy configuration we have two mappings to a controller with the same name, but the namespace attribute defines different version values:
// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {
static mappings = {
// Define mapping to com.mrhaki.grails.api.v1.UserController
// with namespace v1.
"/api/v1/users"(resource: 'user', namespace: 'v1')
// Define mapping to com.mrhaki.grails.api.v2.UserController
// with namespace v2.
"/api/v2/users"(resource: 'user', namespace: 'v2')
// Other mappings.
"/"(controller: 'apiDoc')
"500"(controller: 'error')
}
}
To create links to controllers with a namespace we can use the new namespace attribute in the link and createLink tags. The following GSP page part shows how we can set the namespace so a correct link is generated:
<h2>Links</h2>
<ul>
<li><g:link controller="report" namespace="user">User Reports</g:link></li>
<li><g:link controller="report" namespace="common">Common Reports</g:link></li>
<li><g:createLink controller="report" namespace="user"/></li>
<li><g:createLink controller="report" namespace="common"/></li>
</ul>
We get the following HTML:
<h2>Links</h2>
<ul>
<li><a href="/namespace-controller/user-report/index">User Reports</a></li>
<li><a href="/namespace-controller/common-report/index">Common Reports</a></li>
<li>/namespace-controller/user-report/index</li>
<li>/namespace-controller/common-report/index</li>
</ul>
Code written with Grails 2.3.2.
Original blog post written on November 15, 2013.
Grouping URL Mappings
We can group URL mappings defined in grails-app/conf/UrlMappings.groovy using the group() method defined for the URL mapping DSL. The first argument is the first part of the URL followed by a closure in which we define mappings like we are used to.
Suppose we have defined the following two mappings in our UrlMappings.groovy file, both starting with /admin:
// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {
static mappings = {
// Mappings starting both with /admin:
"/admin/report/$action?/$id?(.${format})?"(controller: 'report')
"/admin/users/$action?/$id?(.${format})?"(controller: 'userAdmin')
"/"(view:"/index")
"500"(view:'/error')
}
}
We can rewrite this and use the group() method to get the following definition:
// File: grails-app/conf/UrlMappings.groovy
class UrlMappings {
static mappings = {
// Using grouping for mappings starting with /admin:
group("/admin") {
"/report/$action?/$id?(.${format})?"(controller: 'report')
"/users/$action?/$id?(.${format})?"(controller: 'userAdmin')
}
"/"(view:"/index")
"500"(view:'/error')
}
}
When we use the createLink and link tags the group is taken into account. For example when we use <g:createLink controller="userAdmin"/> we get the following URL if the application name is sample: /sample/admin/users.
Code written with Grails 2.3.
Original blog post written on November 18, 2013.