Java 如何在SpringMVC和mongodb中下载文件

Java 如何在SpringMVC和mongodb中下载文件,java,spring,mongodb,spring-mvc,Java,Spring,Mongodb,Spring Mvc,你们已经编写了如下的控制器类。我正在尝试从MongoDB获取文件并尝试下载它 organizationFileAttachmentService.setUser(getUser()); GridFSDBFile file = organizationFileAttachmentService.getGridFSDBFileById(new ObjectId(id), "File"); if (file != null) { byte[] content =

你们已经编写了如下的控制器类。我正在尝试从MongoDB获取文件并尝试下载它

    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");
        }

但我无法下载文件。有人能帮我吗。

如果您没有找到,Spring提供了各种内置的资源处理程序

如果您的方法返回其中的一个,在您的示例中可能是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。以前,products={MediaType.APPLICATION_OCTET_STREAM_VALUE}会导致Spring添加适当的头,现在它将其视为一种限制。如果使用标准web浏览器访问URL,则不会发送应用程序/八位字节流的accept标头。因此,Spring将返回406错误。要使其再次工作,需要在不使用products属性的情况下重新编写此类方法。相反,将HttpServletResponse添加到方法参数,并在方法内部添加头。i、 e:

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET)
@ResponseBody FileSystemResource downloadFile(
            Long fileId, HttpServletResponse response) {
    ...
    response.setHeader( "Content-Disposition", "attachment;filename=" + fileName );
    ...
}
编辑重复:
现在通过Spring Boot 1.1.8使用Spring 4.0.7。似乎设置products={MediaType.APPLICATION_OCTET_STREAM_VALUE}指令现在又开始工作了。对于我尝试过的所有浏览器来说,只要有这个指令就足够了。但是,请注意,我还发现它没有设置内容配置,它保留为application/json。虽然这对浏览器来说似乎不是问题,但我在PHP客户端应用程序中遇到了一些bug,它们的行为似乎只基于内容配置。因此,目前的解决方案似乎是同时完成上述两项工作

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

如果您的方法返回其中的一个,在您的示例中可能是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。以前,products={MediaType.APPLICATION_OCTET_STREAM_VALUE}会导致Spring添加适当的头,现在它将其视为一种限制。如果使用标准web浏览器访问URL,则不会发送应用程序/八位字节流的accept标头。因此,Spring将返回406错误。要使其再次工作,需要在不使用products属性的情况下重新编写此类方法。相反,将HttpServletResponse添加到方法参数,并在方法内部添加头。i、 e:

@RequestMapping(value = "/foo/bar/{fileId}", 
    method = RequestMethod.GET)
@ResponseBody FileSystemResource downloadFile(
            Long fileId, HttpServletResponse response) {
    ...
    response.setHeader( "Content-Disposition", "attachment;filename=" + fileName );
    ...
}
编辑重复:
现在通过Spring Boot 1.1.8使用Spring 4.0.7。似乎设置products={MediaType.APPLICATION_OCTET_STREAM_VALUE}指令现在又开始工作了。对于我尝试过的所有浏览器来说,只要有这个指令就足够了。但是,请注意,我还发现它没有设置内容配置,它保留为application/json。虽然这对浏览器来说似乎不是问题,但我在PHP客户端应用程序中遇到了一些bug,它们的行为似乎只基于内容配置。因此,目前的解决方案似乎是同时完成上述两项工作

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

@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");
        }
    }
}

现在它对我来说工作得很好。

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

@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");
        }
    }
}
现在它对我来说工作正常。

行response.setCharacterEncodingfile.getMD5;这是不正确的。CharacterEncoding必须是UTF-8或类似的代码;这是不正确的。字符编码必须是UTF-8或类似的。