Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render in CSV format in grails

Grails provides Converter class to quickly transform any kind of Java/Groovy objects to either XML/JSON response. Like,

render obj as XML

or

render obj as JSON

I am working on a grails app that requires me to render an object in csv format. Is there a way to do that?

I tried out few stuff and I have explained those below:

Snippet of my code

csv {
    def results = []
    for(d in Data.list()) {
        def r= [d.id, d.name]
        results << r
    }
    def result = ''
    results.each{ row ->
        row.each{
            col -> result += col + ','
        }
        result = result[0..-2]
        result += '\n'
    }
    println result

    render(contentType:'text/csv',text:result)
}

I stored my results in an ArrayList and then converted them to a comma separated string and then passed it to a render method. When I run the above code on the browser, it creates the desired file and the browser pops up a dialog box to "Save As" the file.

When I changed the contentType to text/html, the file contents are displayed on the browser with no newline chars.

Is there a better way to render the contents of the csv file on the browser the same way its on the file.

Thanks.

like image 213
Shenoy Tinny Avatar asked Mar 31 '11 18:03

Shenoy Tinny


3 Answers

So I was just trying to solve the same problem -- responding to a Grails 3 request with a CSV download.

I got a tip from the Grails slack channel to use the Apache Commons CSV code which takes care of the details like handling commas, quotes and other special characters.

To use it, you'll need to add it to your project's dependencies. In build.gradle, under dependencies add:

compile "org.apache.commons:commons-csv:1.2"

Here's an example controller that puts everything together and responds to all requests with the CSV download for the domain object Item.

package name.of.package

import grails.rest.*
import grails.converters.*
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVPrinter

class ItemController extends RestfulController {

    static responseFormats = ['json', 'xml', 'csv']
    ItemController () {
        super(ApprovedHotel)
    }

    def export(Integer max) {

        def items = Item.list()
        withFormat {
            csv {
                def results = []
                for(d in items) {
                    def r= [d.column1, d.column2]
                    results << r
                }

                StringWriter stringWriter = new StringWriter();
                CSVPrinter printer = new CSVPrinter(stringWriter, CSVFormat.EXCEL);
                printer.printRecords( results )
                printer.flush()
                printer.close()
                result = stringWriter.toString()

                response.setHeader("Content-disposition", "attachment; filename=filename.csv")
                render(contentType:'text/csv',text:result)
            }
        }
    }
}
like image 180
sam Avatar answered Nov 06 '22 18:11

sam


You can render the CSV as text/plain instead of text/html. Browsers will render this as plain text, similar to what you'd see if you open the file in an editor.

like image 20
ataylor Avatar answered Nov 06 '22 18:11

ataylor


If you want to display csv data in the browser you need to use

<br>

instead of \n for a new line if you want new lines to be displayed properly in HTML. Browsers generally ignore control characters and only base formatting on HTML tags.
If you want to allow the user to download a csv file code like the following will work.

response.setHeader("Content-disposition", "attachment; filename=Edata.csv")
render(contentType: "text/csv", text:varContainingData )
like image 2
Jared Avatar answered Nov 06 '22 18:11

Jared