Spring - 下载文件并重定向

8
我页面上有一个下载链接,它工作得很好,但它不会刷新/重定向我的页面。这是我的代码。
@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;
}

我已经删除了一些无关的代码,使它变得更短了。我也试过使用@ResponseBody,但结果和上面的代码一样。 任何建议都将有所帮助。

6个回答

10

你无法下载文件并进行刷新/重定向。

我将尝试解释原因。请求流程如下图所示:enter image description here

黄色圆圈代表您的控制器。当您返回视图名称时,前端控制器会查找适当的视图模板(根据配置的视图解析器,通常为jsp、tiles或其他),获取响应并将生成的html(或非html)代码写入其中。

在您的情况下,执行以下操作:

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

此后,由于在其之前进行了操作,Spring无法打开响应并将刷新的页面写入其中。因此,您可以更改方法签名为:

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

删除最后一个"return VIEW_NAME",不会有任何变化。


3

您可以:

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

在URL:“index”响应后1秒钟,刷新页面。


这并没有为我刷新页面... 我用URL替换了“index”,该URL指向我的控制器响应的位置。出了什么问题? - Lansorian

2
它不会。浏览器会在新窗口中打开ms-excel contentType,或者您会得到一个下载提示。发起下载的页面永远没有机会处理重定向或页面转换。
如果需要下载和页面刷新,可以使用JavaScript函数启动下载并将用户引导到下一页,该页面可以显示“您的下载即将开始”或类似的内容。

1
你可以下载后,调用JavaScript函数将其提交到控制器,然后显示不同的页面。

1
我使用以下结构来解决我的问题。该函数提交表单并返回,换句话说,您下载文件并刷新以前的链接。使用此解决方案,甚至可以使用某些模板呈现显示和隐藏消息错误,我在这种情况下使用了Thymeleaf
为了使代码更易读,我删除了Thymeleaf标签。 JS文件:
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 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

LottaLava的回答中,我得到了解决类似问题的想法。

在JavaScript中,表单提交后,我等待一秒半,然后重新加载页面。等待时间是为了让后端下载文件(这里是exportToXML)并返回响应,然后在JavaScript中刷新页面。

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

这里的 form.submit() 调用控制器动作,在你的情况下是 exportToXML

sleep 函数如下:

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

sleep 函数指的是 这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接