您已经编写了如下控制器类。我试图从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");
}
但我无法下载文件。任何人都可以帮助我。
答案 0 :(得分:4)
如果您错过了它,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.而以前,produce = {MediaType.APPLICATION_OCTET_STREAM_VALUE}会导致Spring添加适当的标头,现在它将其视为限制。如果使用标准Web浏览器访问URL,则不会发送“application / octet-stream”的接受标头。因此Spring将返回406错误。为了让它再次工作,需要重写这种方法而不使用“produce”属性。相反,将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
。因此,目前的解决方案似乎是要做到上述两点!
答案 1 :(得分:1)
我已将我的请求更改为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");
}
}
}
现在它对我来说很好。