2

I followed this post for the functionality: client can download a file(ie, csv,pdf and zip) as of now.

But either I am getting pdf which is blank or when trying with zip file, it is coming as damaged. Only CSV works fine.

I have checked the headers, everything seems as per the standard. I am not even using "application/octet-stream" and using "application/pdf" for pdf, "application/csv" for csv and "application/zip" for zip just to avoid any issue with client. I am using swagger 2.4 to test my apis. Here is my code.

@CrossOrigin
@Controller
public class ReportRestController {


@Autowired
ReportService reportService;

@Value("${report.temp.directory}") // used for storing file in local
private String reportLocation;

@ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "Authorization", required = true, dataType = "string", paramType = "header"),
        @ApiImplicitParam(name = "Auth-Provider", value = "Auth-Provider", required = true, dataType = "string", paramType = "header"),})
@RequestMapping(value = "/report/{type}/{format}", method = RequestMethod.POST)
public void getList(@RequestHeader(value = "UserId", required = false) Long userId,
        @RequestHeader(value = "TeamId", required = false) Long teamId,
        @RequestHeader(value = "CustomerId", required = true) Long customerId,
        @PathVariable("type") String type, @PathVariable("format") String formate,
        @RequestBody ReportRequestObj reportobj, HttpServletResponse response) {

    String filename = reportService.getReport(customerId, userId, teamId, type, formate, reportobj);
    Path pathfile = Paths.get(reportLocation, filename);
    File file = pathfile.toFile();
    if (file.exists()) {
        String fileExtension = FilenameUtils.getExtension(filename);
        if(CommonConstants.CSV.equals(fileExtension)){
            response.setContentType("application/csv");
        }else if(CommonConstants.PDF.equals(fileExtension)){
            response.setContentType("application/pdf");
        }else if(CommonConstants.ZIP.equals(fileExtension)){
            response.setContentType("application/zip");
        }
        response.addHeader("Content-Disposition", "attachment; filename=" + filename);
        response.setContentLength((int) file.length());
        response.setHeader("Content-Transfer-Encoding", "binary");
        try(FileInputStream fileInputStream = new FileInputStream(file)) {
            IOUtils.copy(fileInputStream,response.getOutputStream());
            response.getOutputStream().flush();
            //response.flushBuffer();
        } catch (IOException ex) {
            log.error("Error while sending the file:{} for customerId:{} ,userId:{}",
                    file.getPath(), customerId, userId);
        }
    }
}

Please let me know what I am doing wrong or missing ?

EDIT 1: I am attaching the response header I got:

{
 "date": "Sun, 01 Jan 2017 19:11:13 GMT",
 "x-content-type-options": "nosniff",
 "access-control-max-age": "3600",
 "content-disposition": "attachment;   filename=localhost-blob-abcd.pdf",
"content-length": "172962",
"x-xss-protection": "1; mode=block",
"x-application-context": "report-server:8095",
"pragma": "no-cache",
"server": "Apache-Coyote/1.1",
"x-frame-options": "DENY",
"access-control-allow-methods": "POST, PUT, GET, OPTIONS, DELETE",
"content-type": "application/pdf;charset=UTF-8",
"access-control-allow-origin": "*",
"cache-control": "no-cache, no-store, max-age=0, must-revalidate, no-cache",
"access-control-allow-headers": "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, Auth-Provider, UserId, TeamId, Lang, CustomerId",
"expires": "0"
}
Community
  • 1
  • 1
balboa_21
  • 375
  • 1
  • 7
  • 21

1 Answers1

4

Ok, this code works for me:

package com.example;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import javax.servlet.http.HttpServletResponse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Controller
    public class DownloadController {

        @RequestMapping("/download")
        public ResponseEntity<InputStreamResource> download() throws FileNotFoundException {
            final File file = new File("file.pdf");
            return ResponseEntity.ok()
                    .contentLength(file.length())
                    .contentType(MediaType.APPLICATION_PDF)
                    .cacheControl(CacheControl.noCache())
                    .header("Content-Disposition", "attachment; filename=" + file.getName())
                    .body(new InputStreamResource(new FileInputStream(file)));
        }
    }
}

There is nothing specific to Spring Boot, you can use in with plain Spring MVC.

Maybe it is a Swagger issue like this: File download via content-disposition header corrupts file, not a server side one. Have you tried to test this API call with some other tool? For example curl never let me down.

Alexander Yanyshin
  • 1,310
  • 10
  • 8
  • Thanks for the quick response. But the response is same-Black PDF and damaged zip file. – balboa_21 Jan 01 '17 at 15:00
  • @balboa_21 Provided sample code which implements buffered file to response copy with ResponseEntity API. – Alexander Yanyshin Jan 01 '17 at 17:57
  • Hi @yanys, still the same issue. Blank pdf + zip file is corrupted. Only csv is working fine. And sure, i will change the title, I did not know what else to put so I wrote Spring Boot. Thank You. By the way, I am using swagger for testing purpose. – balboa_21 Jan 01 '17 at 19:14
  • 1
    Hi @balboa_21, maybe it is a Swagger issue like [File download via content-disposition header corrupts file](https://github.com/swagger-api/swagger-ui/issues/1605), not a server side one. Have you tried to test this API call with some other tool? For example [curl](https://curl.haxx.se/) never let me down. – Alexander Yanyshin Jan 02 '17 at 09:17
  • Hi @yanys , thanks for letting me know I tried using curl, swagger was generating `curl -X` instead of `curl -o` and it is working perfectly fine. can you put up this comment as an edit to answer so that I can mark it as accepted.I will update the title as well. – balboa_21 Jan 02 '17 at 12:00
  • I am facing the same issue empty pdf : `StringBuilder builder = new StringBuilder(); int numCharsRead; while ((numCharsRead = reader.read(charArray, 0, charArray.length)) != -1) { builder.append(charArray, 0, numCharsRead); } reader.close(); targetArray = builder.toString().getBytes(); is = new ByteArrayInputStream(targetArray); return ResponseEntity.ok().contentLength(targetArray.length).contentType(MediaType.APPLICATION_PDF) .cacheControl(CacheControl.noCache()).header("Content-Disposition", "attachment; filename=" + "t.pdf") .body(new InputStreamResource(is));` – Shivkumar Mallesappa Apr 26 '18 at 11:32
  • I am not understanding the root cause of the issue I am not using Swagger . I have a simple endpoint from where I want to render pdf. I am able to download the pdf but it is blank and if I use "application/octet-stream" I see that contents are there. So what might be the issue ? Thanks – Shivkumar Mallesappa Apr 26 '18 at 11:35