4

This question nicely explains on how to write download file controllers in spring. This question nicely explains that Post request cannot be sent using response.sendRedirect()

I would like the user to be redirected to the same page with an error about what caused file download error. Here is the workflow

  1. User hits www.abc.com/index [controller has mapping /index.jsp and return ModelAndView]
  2. At this page, we have a file download which has URL www.abc.com/download?resource_id=123. [controller has mapping /download and returns void]
  3. When there is error in file download, user should be redirected to www.abc.com/index with some error display.
  4. When there is no error in file download, user stays at the same page and file download dialog appears.

Following is a snippet for forwarding:

@RequestMapping(/download)
public void execute(@RequestParam(value = "resource_id" required = true) final String resource, final HttpServletRequest request, final HttpServletResponse response) {
    try {
        //some processing
    } catch {
        RequestDispatcher dispatcher = request.getRequestDispatcher("/index" + "?is_downloaded=false");
        dispatcher.forward(request, response)
    }
}

@RequestMapping(/index)
public void execute(@RequestParam(value = "is_downloaded" required = false) final String isDownloaded, final HttpServletRequest request) {
    //do stuff here
}

Step 3 is the problem.

  • Using forwarding changes the URL to the download URL of the report on error.
  • Using redirect as response.sendRedirect() with hidden parameters is impossible would not modify the URL at all.
  • Using redirect as response.sendRedirect() with hidden parameters and would introduce "?is_downloaded=false" at the end of URL

Can anyone tell a workaround for this.

Community
  • 1
  • 1
Aman Deep Gautam
  • 8,091
  • 21
  • 74
  • 130
  • 1
    2 ways to solve this, you don't need void as return value, return ModelAndView or String will be much easier. – Jaiwo99 Dec 05 '14 at 23:56

1 Answers1

1

I've been having a similar issue and solved it with the below code.

I have the following exception handler in my controller. If there is an error this takes care of the re-direct and error messaging.

@ExceptionHandler(FileNotFoundException.class)
public ModelAndView exceptionHandler(Exception ex) {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("rescues/general");
    modelAndView.addObject("message", ex.getMessage());
    return modelAndView;
}

Here is the RequestMapping

@RequestMapping(value = "s3Download.request", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> download(@RequestParam(value = "s3key") String s3Key)
        throws IOException {
    HttpHeaders responseHeaders = new HttpHeaders();
    InputStreamResource inputStreamResource = s3DownloadService.getS3File(s3Key, responseHeaders);
    return new ResponseEntity<>(inputStreamResource, responseHeaders, HttpStatus.OK);
}

If the files are locally on your server you can use a FileSystemResource in place of the InputStreamResource.

The service layer takes care of setting the response header values on the HttpHeaders object

responseHeaders.setContentType(MediaType.parseMediaType(objectMetaData.getContentType()));
responseHeaders.setContentLength(objectMetaData.getContentLength());
responseHeaders.setContentDispositionFormData("attachment", fileName);
Draukadin
  • 79
  • 7
  • Hi, @Draukadin, I added exceptionHandler() method to my spring boot application. Method is being called, but, browser is not showing the error page. Instead 0 sized file is created. Am I missing anything? The html code on the browser side is `` – Rupesh Dec 13 '21 at 19:16