【发布时间】:2016-10-29 11:23:46
【问题描述】:
当我尝试使用 Spring Boot 和 Spring MVC 下载压缩文件时出现错误: 错误:
- 严重:Servlet.service() 用于路径 [] 上下文中的 servlet [dispatcherServlet] 引发异常 [请求处理失败;嵌套异常是 java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed] 根本原因 java.lang.IllegalStateException:响应提交后无法调用 sendRedirect()
- 严重:Servlet DispatcherServlet 的 Servlet.service() 引发异常 java.lang.IllegalStateException: getOutputStream() 已为此响应调用
基本上,我的应用正在加载一个文件,对其进行压缩并下载新的 zip 文件。
这是我的应用控制器:
@Controller
public class ApplicationController {
public String fileZipped;
public String inputFile;
@RequestMapping(method = RequestMethod.GET, value = "/uploadForm")
public String provideUploadInfo() {
return "uploadForm";
}
@RequestMapping(method = RequestMethod.POST, value = "/")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes,
HttpServletResponse downloadResponse) {
if (!file.isEmpty()) {
try {
inputFile = file.getOriginalFilename();
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File(Application.UPLOAD_DIR + "/" + inputFile)));
FileCopyUtils.copy(file.getInputStream(), stream);
stream.close();
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
FileUtils.copyDirectory(Application.UPLOAD_DIR, Application.OUTPUT_FOLDER);
FileUtils.cleanDirectory(new File(Application.UPLOAD_DIR));
}
catch (Exception e) {
redirectAttributes.addFlashAttribute("message",
"You failed to upload " + file.getOriginalFilename() + " => " + e.getMessage());
}
}
else {
redirectAttributes.addFlashAttribute("message",
"You failed to upload " + file.getOriginalFilename() + " because the file was empty");
}
return "redirect:/zipFiles";
}
@RequestMapping(value = "/download")
public String handleFileDownload(HttpServletResponse downloadResponse) throws IOException {
InputStream inputStream = null;
OutputStream outStream = null;
try {
if ( fileZipped!=null && Files.exists(Paths.get(fileZipped))) {
inputStream = new FileInputStream(fileZipped);
downloadResponse.setContentType(fileZipped);
downloadResponse.addHeader("Content-Disposition", "attachment; filename=" + Paths.get(fileZipped).getFileName().toString());
outStream = downloadResponse.getOutputStream();
org.apache.commons.io.IOUtils.copy(inputStream, outStream);
downloadResponse.flushBuffer();
}
} catch (IOException e) {
throw new RuntimeException("IOError writing file to output stream");
} finally {
if (inputStream != null) inputStream.close();
if (outStream != null) outStream.close();
}
return "redirect:/uploadForm";
}
@RequestMapping(value="/zipFiles")
public String handleFileZip() throws IOException {
if(inputFile!=null) {
fileZipped = zipFiles(Application.OUTPUT_FOLDER, inputFile);
}
return "redirect:/download";
}
private String zipFiles(String folder, String zipFileName) throws IOException {
String zipFile = folder + "/" + FilenameUtils.removeExtension(zipFileName) + ".zip";
FileOutputStream fileOutputstream = new FileOutputStream(zipFile);
ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(fileOutputstream));
File []filesArray = new File(folder).listFiles();
for (File file : filesArray){
if (!FilenameUtils.getExtension(file.getAbsolutePath()).equals("zip")) {
byte[] buffer = new byte[1024];
FileInputStream fileInputStream = new FileInputStream(file);
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
int length;
while ((length = fileInputStream.read()) > 0) {
zipOutputStream.write(buffer, 0, length);
}
zipOutputStream.closeEntry();
fileInputStream.close();
}
}
zipOutputStream.close();
return zipFile;
}
如果我关闭输入和输出流,我不知道为什么会发生这种情况。
非常感谢您的帮助。
【问题讨论】:
-
您不能流式传输某些内容然后重定向。您可以流式传输结果或重定向,但不能两者兼而有之。基本上你的下载方法是错误的。
-
这就是 Servlet 规范的工作方式。在刷新任何内容之前,您需要确定是否需要重定向。所以你不能发送文件+重定向。你只能做其中之一。
-
感谢@Augusto。我已将下载方法修改为:public void handleFileDownload... 并且它可以工作(没有错误)并且应用程序停留在 uploadForm 视图中(localhost:8080/uploadForm)。但现在我不明白为什么应用程序停留在这个视图(localhost:8080/uploadForm)而不是最后一个重定向视图(localhost:8080/download)。
-
也感谢@M.Deinum!
-
如何再次加载uploadForm 视图?
标签: spring spring-mvc spring-boot