求助: springmvc 上传至 mongodb 后下载文件无法打开

2019-02-01 10:27:48 +08:00
 arseBurger
RT 球球大佬们帮忙看看是哪里出了问题
----上传


/**
*
*接受前端上传的文件并存储至 MongoDB
* @param file 前端上传的文件
* @return 处理结果信息
*/
@CrossOrigin
@ResponseBody
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ReturnInfo fileUpload(@RequestParam MultipartFile file) throws Exception {
ReturnInfo<Map> info = new ReturnInfo<>();
if (!file.isEmpty()) {
BufferedInputStream inputStream = new BufferedInputStream(file.getInputStream());
String fileId = fileService.fileUpload(inputStream);
info.setCode(ReturnInfo.OK);
info.setMessage("上传成功!");
Map<String, String> resultMap = new HashMap<>();
resultMap.put("fileId", fileId);
info.setData(resultMap);
return info;
} else {
info.setMessage("文件不能为空");
info.setCode(ReturnInfo.ERROR);
return info;
}

}

/**
* 文件上传 service
*
* @param fileInput 文件输入流
* @return mongodb 对应文件 id
*/
@Override
public String fileUpload(InputStream fileInput) throws RestServiceException {
String fileType = FileUtil.getFileType(fileInput);
System.out.println(fileType);
//文件类型判断
if (!FileUtil.ENABLE_TYPES.contains(fileType)) {
throw new RestServiceException("不支持的文件类型!");
}
GridFSFile uploadFile = gridFsTemplate.store(fileInput, StringUtil.getUUID(), fileType);
return uploadFile.getId().toString();
}

----下载





/**下载请求
* 下载文件
*
* @param fileId 文件 ID
* @return
*/
@CrossOrigin
@RequestMapping(value = "/download2/{fileId}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> fileDownload2(@PathVariable String fileId) throws Exception {
//从 MongoDB 获取文件
GridFSDBFile file = fileService.getFileById(fileId);
String fileType = file.getContentType();
//设置文件 ContentType
MediaType mediaType = FileUtil.getEnableStr(fileType);
InputStreamResource resource = new InputStreamResource(file.getInputStream());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(mediaType);
headers.setContentDispositionFormData("attachment",file.getFilename()+"."+fileType);
//返回前端
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

/**
*下载 service
*/
@Override
public GridFSDBFile getFileById(String fileId) throws RestServiceException {
GridFSDBFile file = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
if (file == null) {
throw new RestServiceException("找不到相关文件!请检查 fileId");
}
return file;
}
1608 次点击
所在节点    问与答
10 条回复
arseBurger
2019-02-01 11:10:10 +08:00
在吗? 看看题 : (
arseBurger
2019-02-01 11:23:34 +08:00
99 可怜的新手
gz911122
2019-02-01 12:12:59 +08:00
不是 我就想问问文件存 MongoDB 是什么操作
这玩意不应该都是存静态资源服务器,cdn 啥的吗
undeflife
2019-02-01 12:26:14 +08:00
@gz911122 存的是 mongodb 的 GridFS
undeflife
2019-02-01 12:30:36 +08:00
打不开是什么效果?没有后缀? 还是内容有问题?
String fileType = file.getContentType();这里的 fileType 是对的吗
下载后的文件 hash 对吗?
arseBurger
2019-02-01 13:28:34 +08:00
@undeflife 感谢回复,fileType 是存到 GridFs 里的文件后缀名,如下记录:
{
"filename" : "3514bd478bbe476b8628daa5d2f03156",
"aliases" : null,
"chunkSize" : NumberLong(261120),
"uploadDate" : ISODate("2019-01-31T05:20:51.364+0000"),
"length" : NumberLong(6035),
"_id" : ObjectId("5c5285b32293366f443d190d"),
"contentType" : "txt",
"md5" : "06d90ff5b133aceecd080fdcff475b1b"
}

我试了一下下载 FileSystem 上的文件同样有这个问题,应该可以排除 mongodb 存储的问题了
arseBurger
2019-02-01 13:45:12 +08:00
@undeflife ....修改一下...FileSystem 上的文件下载只有 Txt 能正常打开,其他的还是不行 :(
这段是判断文件类型的方法:
/**
* 根据制定文件的文件头判断其文件类型
*
* @param
* @return
*/
public static String getFileType(InputStream inputStream) {
String res = null;
try {
byte[] b = new byte[10];
inputStream.read(b, 0, b.length);
String fileCode = bytesToHexString(b);

System.out.println(fileCode);

//这种方法在字典的头代码不够位数的时候可以用但是速度相对慢一点
Iterator<String> keyIter = FILE_TYPE_MAP.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next();
if (key.toLowerCase().startsWith(fileCode.toLowerCase()) || fileCode.toLowerCase().startsWith(key.toLowerCase())) {
res = FILE_TYPE_MAP.get(key);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return res;
}

这段是匹配 MediaType 的方法:
/**
* @param fileType
* @return
*/
public static MediaType getEnableStr(String fileType) {
if (IMAGE_TYPES.contains(fileType)) {
return MediaType.valueOf("image/" + fileType);
} else if (PDF_TYPES.contains(fileType)) {
return MediaType.APPLICATION_PDF;
} else if (TXT_TYPES.contains(fileType)) {
return MediaType.TEXT_PLAIN;
} else {
return MediaType.APPLICATION_OCTET_STREAM;
}
}
undeflife
2019-02-01 13:55:42 +08:00
@arseBurger 不是 你一直没表达清楚的是 "无法打开" 是浏览器直接打开 还是下载到本地后不能打开? 不能打开又是什么效果?
arseBurger
2019-02-01 14:42:57 +08:00
@undeflife 嗯嗯,不好意思,我没表述清楚,是下载到本地后无法打开,照片类型的提示无法打开此文件,doc 文档提示发现有无法读取的内容,mp4 文件提示此文件无法播放。这可能是因为文件类型不受支持、文件扩展名不正确或文件已损坏。
undeflife
2019-02-01 16:12:31 +08:00
@arseBurger 你的代码我没细看 粗看没太大问题 我觉得你比对文件在各个装下的 md5 是不是都一致
另外我记得 gridfs 的封装里 contentType 这个字段本身就是 MIME type 感觉你这部分处理有点不对 甚至直接作为附件的文件后缀了.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/532360

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX