Spring - download file and redirect

I have a download link on my page that works fine but does not refresh / redirect my page. Here is my code.

@RequestMapping(method = RequestMethod.POST, params = "exportToXML") public String exportToXML(HttpServletResponse response, Model model, @ModelAttribute(FILTER_FORM) ScreenModel form, BindingResult result, OutputStream out, HttpSession session) throws IOException { ZipOutputStream zipout; ByteArrayOutputStream baos = new ByteArrayOutputStream(); zipout = new ZipOutputStream(baos); ZipEntry ze = new ZipEntry("file.xml"); zipout.putNextEntry(ze); zipout.write(string.getBytes()); zipout.closeEntry(); zipout.close(); baos.close(); response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-disposition", "attachment; filename=xx.zip"); response.getOutputStream().write(baos.toByteArray()); response.getOutputStream().close(); response.getOutputStream().flush(); return VIEW_NAME; } 

I removed unnecessary code snippets to make it a little shorter. I also tried with @ResponseBody, but it gives the same result as the code above. Any advice would be helpful

+5
source share
6 answers

You cannot upload a file and update / redirect. I will try to explain the reasons. The flow of requests is shown here: enter image description here

where the yellow circle is your controller. When you return the name of the view, the front controller looks for the appropriate view template (just jsp, tiles, or others, depending on the view resolution configured), receives a response and writes the generated html code (or not html).

In your case, you do the following:

 response.getOutputStream().write(baos.toByteArray()); response.getOutputStream().close(); response.getOutputStream().flush(); 

After this action, spring will not be able to open the response and write an updated page (because you are doing this earlier). Thus, you can change your method signature to:

 public void exportToXML(HttpServletResponse response, Model model, @ModelAttribute(FILTER_FORM) ScreenModel form, BindingResult result, OutputStream out, HttpSession session) throws IOException { 

and delete the last "return VIEW_NAME". Nothing will change.

+8
source

You can:

 response.setHeader("Refresh", "1; url = index"); 

This is a page refresh 1 second after responding to the URL: "index".

+3
source

This is not true. The browser opens ms-excel contentType in a new window or you will receive a download prompt. The page on which the download was loaded will never be able to handle redirection or transition to the page.

If you need to update the download + page, the JavaScript function can initiate the download and direct the user to the next page, on this page you can say that "your download will start soon" or something like that.

+2
source

After loading, you can call the javascript function to send you a controller, and they show another page.

+1
source

From LottaLava's answer, I got an idea to solve a similar problem.

In JavaScript, after submitting the form, I wait a second and a half, and then reload the page. The wait time is the time when the backend downloads the file (here exportToXML ) and returns a response, and then refreshes the page in JavaScript.

 form.submit(); sleep(1500).then(function() { document.location.reload(); }); 

Here form.submit() calls the action of the controllers, in your case exportToXML .

The sleep function is as follows:

 function sleep(milliseconds) { return new Promise(function (resolve) { setTimeout(resolve, milliseconds); }); } 

The sleep function is referenced here.

0
source

I used the following structure to solve my problem. The function of submitting the form and back, in other words, you download the file and update the previous link. Using this solution, you can even show and hide error messages using some render template, in my case I used Thymeleaf .

To make the code more readable, I removed the Thymeleaf tags.

Js file:

 function submitAndBack(formId) { let formDoc = document.getElementById(formId); formDoc.submit(); sleep(1000).then(function() { window.history.back(); }); } function sleep(milliseconds) { return new Promise(function (resolve) { setTimeout(resolve, milliseconds); }); } 

HTML form:

 <form id="myForm" method="POST" action="/some/url"> <label for="inputText">Some info</label> <input id="inputText" name="inputText" type="text"> <button onclick="submitAndBack('myForm')"> Submit </button> </form> 
0
source

Source: https://habr.com/ru/post/1497439/


All Articles