2

I was trying to make a rest endpoint in Spring Boot which reads from DB, generates an excel file(Using Apache POI) which is returned to the user using HttpServletResponse but when I invoke this, the excel is getting created but it's not downloading. I had some other code earlier in place which was working fine but I accidentally removed that and now I'm stuck. Any help/leads are appreciated.

@RequestMapping(path = "/save", method = RequestMethod.GET)
public ResponseEntity<String> saveToXls(@RequestParam String id, @RequestParam String appName, HttpServletResponse response) {
    AppInstance appInstance = appInstanceRepo.get(id);
    List<DownloadDetail> downloadDetailList = downloadDAO.searchByInstanceId(id);
    //List<DownloadDetail> downloadDetailList = appInstance.getDownloads();
    System.out.print("LIST SIZE:" + downloadDetailList.size());
    String fileName = appName + " report";
    File myFile = new File(fileName + ".xls");

    FileOutputStream fileOut;
    downloadDetailList.forEach(downloadDetail -> System.out.print(downloadDetail.getSid()));
    try {

        try (HSSFWorkbook workbook = new HSSFWorkbook()) {
            HSSFSheet sheet = workbook.createSheet("lawix10");
            HSSFRow rowhead = sheet.createRow((short) 0);
            rowhead.createCell((short) 0).setCellValue("SID");
            rowhead.createCell((short) 1).setCellValue("Download Time");
            rowhead.createCell((short) 2).setCellValue("OS Version");
            int i = 0;

            for (DownloadDetail downloadDetail : downloadDetailList) {
                System.out.print("In loop -2");
                HSSFRow row = sheet.createRow((short) i);
                row.createCell((short) 0).setCellValue(downloadDetail.getSid());
                row.createCell((short) 1).setCellValue(downloadDetail.getDownloadTime());
                row.createCell((short) 2).setCellValue(downloadDetail.getOsVersion());
                i++;
            }
            fileOut = new FileOutputStream(myFile);
            workbook.write(fileOut);
        }
        fileOut.close();

        byte[] buffer = new byte[10240];
        response.addHeader("Content-disposition", "attachment; filename=test.xls");
        response.setContentType("application/vnd.ms-excel");
        try (
                InputStream input = new FileInputStream(myFile);
                OutputStream output = response.getOutputStream();
        ) {
            for (int length = 0; (length = input.read(buffer)) > 0;) {
                output.write(buffer, 0, length);
            }
        }

        response.flushBuffer();

    } catch (FileNotFoundException e1) {
        e1.printStackTrace();
    } catch (IOException e1) {
        e1.printStackTrace();
    }


    return null;
}

EDIT: I tried to do it another way as shown below:

        try (InputStream is = new FileInputStream(myFile)) {
            response.addHeader("Content-disposition", "attachment; filename=test.xls");
            response.setContentType("application/vnd.ms-excel");
            IOUtils.copy(is, response.getOutputStream());

        }
    response.flushBuffer();

This also doesn't seem to cut it.

3 Answers 3

1

This is a my example. Probably the issue is how you manage the OutputStream:

ServletOutputStream os = response.getOutputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\""+fileName+".xls\"");

workbook = excelStrategyMap.get(strategy).export(idList, status, params);

workbook.write(os);
workbook.close();
os.flush();

response.flushBuffer(); 
Sign up to request clarification or add additional context in comments.

1 Comment

It doesn't do anything and still the file download is not happening.
0

Once you get the workbook file, set the file name and file type. and add the response header and content type as mentioned below.

Then write the file to the response and flush it's buffer.

        XSSFWorkbook file = excelUploadService.downloadDocument();
        String filename = "Export.xlsx";
        String filetype = "xlsx";
        response.addHeader("Content-disposition", "attachment;filename=" + filename);
        response.setContentType(filetype);
        // Copy the stream to the response's output stream.

        file.write(response.getOutputStream());
        response.flushBuffer();

In the client side, get the response from the REST API and set the content type received by the response object. Using FileSaver library save the file into your local file system.

Here is the documentation for FileSaver js -- File saver JS Library

        var type = response.headers("Content-Type");
        var blob = new Blob([response.data], {type: type});

        saveAs(blob, 'Export Data'+ '.xlsx');

Comments

0
@GetMapping(value = "/", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
@ResponseBody
public byte[] generateExcel() {
        byte[] res = statisticsService.generateExcel();
        return res;

3 Comments

Its nice to add little explanation to the code for easier understanding.
It shows when you have a list of bytes that you want to return as excel sheet to be downloaded from the browser. So the key is to mention the produces as i did and to add the annotation @ResponseBody with a return type byte[]
your generateExcel would need to return an array of bytes, that could be implemented like this: ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { workbook.write(bos); } finally { bos.close(); } workbook.close(); return bos.toByteArray();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.