【问题标题】:How to download file in Spring mvc and mongodb如何在 Spring mvc 和 mongodb 中下载文件
【发布时间】:2013-11-09 16:23:58
【问题描述】:

您好,编写了如下所示的控制器类。我正在尝试从 mongo db 获取文件并尝试下载它。

    organizationFileAttachmentService.setUser(getUser());
    GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
    if (file != null) {
        byte[] content = organizationFileAttachmentService.findByIdAndBucket(new ObjectId(id), "File");
        try {
            int size = content.length;
            InputStream is = null;
            byte[] b = new byte[size];
            try {
                is = new ByteArrayInputStream(content);
                is.read(b);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (is != null)
                        is.close();
                } catch (Exception ex) {

                }
            }
            response.setContentType(file.getContentType());
            // String attachment =
            // "attachment; filename=\""+file.getFilename()+"\"";
            String attachment = "attachment; filename=" + file.getFilename();
            // response.setContentLength(new
            // Long(file.getLength()).intValue());
            response.setCharacterEncoding(file.getMD5());
            response.setHeader("content-Disposition", attachment);// "attachment;filename=test.xls"
            // copy it to response's OutputStream
            // FileCopyUtils.copy(is, response.getOutputStream());
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
            is.close();
        } catch (IOException ex) {
            _logger.info("Error writing file to output stream. Filename was '" + id + "'");
            throw new RuntimeException("IOError writing file to output stream");
        }

但我无法下载文件。谁能帮帮我。

【问题讨论】:

  • response.setCharacterEncoding(file.getMD5()); 行不正确。 CharacterEncoding 必须是“UTF-8”或类似的。

标签: java spring mongodb spring-mvc


【解决方案1】:

如果你错过了,Spring 提供了各种内置的资源处理程序。

http://docs.spring.io/spring/docs/3.2.5.RELEASE/spring-framework-reference/html/resources.html#resources-implementations

如果您的方法返回其中之一(在您的情况下可能是 ByteArrayResource),那么您只需要在接口上添加几个注释,如下所示:

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET, 
    produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
@ResponseBody FileSystemResource downloadFile(Long fileId);

这样你就不用摆弄编码和标题了。我建议您在自己动手之前尝试一下。

编辑:以上在 Spring 3.1.4 中运行良好。它不再适用于 3.2.x 或 4.x。以前,produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE } 会导致 Spring 添加适当的标头,现在它将其视为限制。如果使用标准 Web 浏览器访问 URL,则不会发送“application/octet-stream”的接受标头。因此 Spring 将返回 406 错误。为了让它再次工作,需要在没有“produces”属性的情况下重新编写这样的方法。相反,将 HttpServletResponse 添加到方法参数并在方法内添加标头。即:

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET)
@ResponseBody FileSystemResource downloadFile(
            Long fileId, HttpServletResponse response) {
    ...
    response.setHeader( "Content-Disposition", "attachment;filename=" + fileName );
    ...
}

编辑redux: 现在通过 Spring Boot 1.1.8 使用 Spring 4.0.7。看来设置produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE } 指令现在又可以工作了。对于我尝试过的所有浏览器来说,只要有这个指令似乎就足够了。但是请注意,我还发现它没有设置Content-Disposition,它保留为application/json。尽管这对于浏览器来说似乎不是问题,但我在 PHP 客户端应用程序中遇到了错误,这些错误似乎仅基于 Content-Disposition。所以看来目前的解决方案是以上两个都做!

【讨论】:

    【解决方案2】:

    我已将我的请求更改为 GET,并在 html 的锚标记中添加了请求。 Aslo 将我的代码更改为

    @RequestMapping(value = "/getFileById/{id}", method = RequestMethod.GET)
    public @ResponseBody
    void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
        organizationFileAttachmentService.setUser(getUser());
        GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File");
        if (file != null) {
            try {
                response.setContentType(file.getContentType());
                response.setContentLength((new Long(file.getLength()).intValue()));
                response.setHeader("content-Disposition", "attachment; filename=" + file.getFilename());// "attachment;filename=test.xls"
                // copy it to response's OutputStream
                IOUtils.copyLarge(file.getInputStream(), response.getOutputStream());
            } catch (IOException ex) {
                _logger.info("Error writing file to output stream. Filename was '" + id + "'");
                throw new RuntimeException("IOError writing file to output stream");
            }
        }
    }
    

    现在它对我来说很好用。

    【讨论】:

      猜你喜欢
      • 2018-02-21
      • 2017-06-10
      • 2013-09-22
      • 1970-01-01
      • 2021-03-07
      • 2023-03-09
      • 2014-07-09
      • 2014-09-26
      • 1970-01-01
      相关资源
      最近更新 更多