Loading...

September 5, 2013

Grails Goodness: 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