Spring - download file and redirect

2020-02-26 12:20发布

I have a download link on my page which works just fine but it doesn't refresh/redirects my page. Here's 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've removed irrelevant pieces of code to make it a little bit shorter. I have also tried with @ResponseBody but it gives the same result as code above. Any advice will be helpful

6条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-02-26 13:01

From LottaLava answer, I got the idea to solve a similar problem.

In JavaScript, after form submission, I wait for one and a half-second and then reload the page. The waiting time is to time for the backend to download the file (here exportToXML) and return the response and then in JavaScript refresh the page.

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

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

The sleep function is as follows:

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

The sleep function refers to here

查看更多
The star\"
3楼-- · 2020-02-26 13:09

You can:

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

This refresh the page after 1 second after response on URL: "index".

查看更多
Animai°情兽
4楼-- · 2020-02-26 13:15

It will not. The browser opens the ms-excel contentType in a new window or you get a download prompt. The page that initiated download never get a chance to handle the redirect or page transition.

If the download + page refresh is desired, a JavaScript function could initiate the download and direct the user to next page, that page could say 'your download will commence shortly' or something similar.

查看更多
我只想做你的唯一
5楼-- · 2020-02-26 13:21

You can't download file and make refresh/redirect. I'll try to explain causes. Request flow is illustrated here: enter image description here

where yellow circle is your controller. When you return view name front controller looks for appropriate view template (simply jsp, tiles or other, depending on configured view resolver) gets response and write generated html (or not html) code to it.

In your case you perform actions:

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

After that actions spring can't open response and write refreshed page to it (because you do it before). So 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 last "return VIEW_NAME". Nothing will change.

查看更多
ら.Afraid
6楼-- · 2020-02-26 13:21

I used the following structure to solve my problem. The function submit the form and back, in other words, you download the file and refresh the previous link. Using this solution, you can even show and hide messages errors with some template render, 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>
查看更多
叛逆
7楼-- · 2020-02-26 13:23

You could after download, call a javascript function to submit to you controller and them show a different page.

查看更多
登录 后发表回答