0

I'm currently working on a web application using grails. One of the requirements is to generate excel timesheets and download it afterword. This is my code for downloading from grails controller.

response.contentType = "application/vnd.ms-excel"
response.setHeader("Content-Disposition","attachment;filename=name.xls")
response.outputStream << wb.bytes
response.outputStream.flush()

But my excel file is corrupted. I can open it using open office, but doesn't work using microsoft office or google drive. Looks like the content of the xls file is not well formatted. If I save document instead of downloading everything is ok.

 FileOutputStream fileOut = new FileOutputStream("name.xls")
 wb.write(fileOut)
 fileOut.close()

I cannot figured out why the file content is corrupted when downloaded as byte array.

Grails version - 2.3.7 Apache poi version - 3.13

Thanks in advance,

Method code

   def generate(){

    TimeSheetExportWrapper timeSheet = new TimeSheetExportWrapper()
    bindData(timeSheet, params.ts)

    HSSFWorkbook wb = excelExportService.createExcelTimeSheet(getCurrentTenant(), timeSheet, getCurrentTimezone())

    response.contentType = "application/vnd.ms-excel"
    response.setHeader("Content-Disposition", "attachment;filename=${timeSheet.proposedFileName}")
    response.outputStream << wb.bytes
    response.outputStream.flush()
}
aelve
  • 119
  • 1
  • 10
  • Post your entire controller method. It might be something before/after what you have posted. – Joshua Moore Mar 22 '16 at 13:59
  • http://stackoverflow.com/questions/15387243/apache-poi-working-with-xssfworkbok-servlet-response I have got it working using this method – V H Mar 22 '16 at 14:05
  • 1
    There are a few things you should do. 1. Add the content length to the header, 2. close the outputStream `response.outputStream.close()` and 3. `return null` after you close the stream so Grails doesn't try and render any view. – Joshua Moore Mar 22 '16 at 14:08

1 Answers1

1

There are a few things that you should be doing:

First, set the content length: response.setHeader("Content-Length", "${wb.bytes.length}")

Secondly, close the output: response.outputStream.close()

And finally, make sure you return null to ensure Grails does not attempt to render a view.

   def generate(){

    TimeSheetExportWrapper timeSheet = new TimeSheetExportWrapper()
    bindData(timeSheet, params.ts)

    HSSFWorkbook wb = excelExportService.createExcelTimeSheet(getCurrentTenant(), timeSheet, getCurrentTimezone())

    response.contentType = "application/vnd.ms-excel"
    response.setHeader("Content-Length", "${wb.bytes.length}")
    response.setHeader("Content-Disposition", "attachment;filename=${timeSheet.proposedFileName}")
    response.outputStream << wb.bytes
    response.outputStream.flush()
    response.outputStream.close()
    return null
}
Joshua Moore
  • 24,706
  • 6
  • 50
  • 73