原文: https://howtodoinjava.com/spring-mvc/spring-mvc-download-file-controller-example/

Spring MVC 应用程序中,要将文件之类的资源下载到浏览器,您需要在控制器中执行以下操作。

  1. void返回类型用于您的请求处理方法,然后将HttpServletResponse添加为该方法的参数。
  2. 将响应的内容类型设置为文件的内容类型。 如果您不知道内容类型是什么,或者希望浏览器始终显示Save As对话框,请将其设置为APPLICATION/OCTET-STREAM (不区分大小写)。
  3. 添加一个名为Content-Disposition的 HTTP 响应标头,并为其赋予值attachment; filename=fileName,其中fileName是应出现在“文件下载”对话框中的默认文件名。

1. Sping MVC 文件下载控制器

让我们看一下文件下载控制器的示例实现。

  1. @Controller
  2. @RequestMapping("/download")
  3. public class FileDownloadController
  4. {
  5. @RequestMapping("/pdf/{fileName:.+}")
  6. public void downloadPDFResource( HttpServletRequest request,
  7. HttpServletResponse response,
  8. @PathVariable("fileName") String fileName)
  9. {
  10. //If user is not authorized - he should be thrown out from here itself
  11. //Authorized user will download the file
  12. String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/downloads/pdf/");
  13. Path file = Paths.get(dataDirectory, fileName);
  14. if (Files.exists(file))
  15. {
  16. response.setContentType("application/pdf");
  17. response.addHeader("Content-Disposition", "attachment; filename="+fileName);
  18. try
  19. {
  20. Files.copy(file, response.getOutputStream());
  21. response.getOutputStream().flush();
  22. }
  23. catch (IOException ex) {
  24. ex.printStackTrace();
  25. }
  26. }
  27. }
  28. }

如果您只想为授权用户启用下载功能,请先在该方法中检查用户的登录状态,然后再允许下载,否则将其重定向到登录屏幕。

现在,如果您点击应用程序 URL:http://localhost:8080/springmvcexample/download/pdf/sample.pdf,您将能够在浏览器中获得另存为对话框,如下所示:

Spring MVC 下载文件控制器示例 - 图1

文件下载窗口

该文件位于文件夹/WEB-INF/downloads/pdf中。 您可以自由更改路径 – 确保同时更改控制器代码。

Spring MVC 下载文件控制器示例 - 图2

文件下载项目结构

2. 防止文件下载的交叉引用

很多时候,其他网站可能会作为直接链接交叉引用您网站中的文件。 您可能不想允许它。 要禁止来自其他域的所有下载请求,您可以检查referer标头中是否包含您的域名。

仅当referer标头不为null时,我们修改后的FileDownloadController才会将文件发送到浏览器。 这将防止通过在浏览器中键入图像的 URL 或来自其他域的请求来直接下载图像。

  1. @Controller
  2. @RequestMapping("/download")
  3. public class FileDownloadController
  4. {
  5. @RequestMapping("/pdf/{fileName:.+}")
  6. public void downloadPDFResource( HttpServletRequest request,
  7. HttpServletResponse response,
  8. @PathVariable("fileName") String fileName,
  9. @RequestHeader String referer)
  10. {
  11. //Check the renderer
  12. if(referer != null && !referer.isEmpty()) {
  13. //do nothing
  14. //or send error
  15. }
  16. //If user is not authorized - he should be thrown out from here itself
  17. //Authorized user will download the file
  18. String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/downloads/pdf/");
  19. Path file = Paths.get(dataDirectory, fileName);
  20. if (Files.exists(file))
  21. {
  22. response.setContentType("application/pdf");
  23. response.addHeader("Content-Disposition", "attachment; filename="+fileName);
  24. try
  25. {
  26. Files.copy(file, response.getOutputStream());
  27. response.getOutputStream().flush();
  28. }
  29. catch (IOException ex) {
  30. ex.printStackTrace();
  31. }
  32. }
  33. }
  34. }

现在,如果您尝试直接从浏览器中访问 URL,则会收到此错误:

  1. java.lang.IllegalStateException: Missing header 'referer' of type [java.lang.String]
  2. at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.raiseMissingHeaderException(HandlerMethodInvoker.java:797)
  3. at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestHeader(HandlerMethodInvoker.java:566)
  4. at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:355)
  5. at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:172)
  6. at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)

将我的问题放在评论部分。

学习愉快!