今天遇到 Seaweed 的一个bug,调用 FileTemplate 的 getFileStatus(String fileId)方法报 NullPointer 。
由于之前未使用过分布式的文件服务器,看了小半天的时间,尝试了一些办法,终于找到了根本原因去解决。假设推理果然是屡试不爽啊。
那我先贴上报空指针的代码(相信大家都会直接这样用,可能也会遇到我这种问题):
1、上传附件 代码
/** * @Description: 上传附件接口 * @Date: 2019/12/19 */ @PostMapping("/upload") @ApiOperation(value = "上传附件接口", notes = "上传附件,上传成功返回附件id") public RestResponse uploadFile(@RequestParam(name = "fileId",required = false) String fileId, @RequestParam("excelFile") MultipartFile file) throws IOException { try { if (file.isEmpty()) { return RestResponse.fail().setMsg("上传文件不能为空!"); } if (!StringUtils.isEmpty(fileId)){ return RestResponse.ok(template.updateFileByStream(fileId,file.getOriginalFilename(),file.getInputStream())); } return RestResponse.ok(template.saveFileByStream(file.getOriginalFilename(), file.getInputStream())); } catch (Exception e) { logger.error("上传附件失败", e); return RestResponse.fail().setMsg("上传附件服务连接关闭"); } } 2、获取附件详情 代码
** * 获取附件的详情 * @return */ @GetMapping("/getFileInfo/{fileId}") @ApiOperation(value="公共下载附件接口",notes = "下载附件接口") @ApiImplicitParams(value = {@ApiImplicitParam(name = "fileId", value = "附件id", dataType = "String", required = true)}) public RestResponse getFileInfo(@PathVariable String fileId) throws IOException { FileHandleStatus status = template.getFileStatus(fileId); return RestResponse.ok(status ); } 解决步骤:
一、debug之后发现是由于 getFileStatus ()方法里 headerResponse 里无 Content-Type 这个头部信息,导致 new FileHandleStatus 的时候报空指针
public FileHandleStatus getFileStatus(String fileId) throws IOException { String targetUrl = this.getTargetUrl(fileId); HeaderResponse headerResponse = this.volumeWrapper.getFileStatusHeader(targetUrl, fileId);
try {
return new FileHandleStatus(fileId, headerDateFormat.parse(headerResponse.getLastHeader("Last-Modified").getValue()).getTime(), headerResponse.getLastHeader("Content-Disposition").getValue().substring(10, headerResponse.getLastHeader("Content-Disposition").getValue().length() - 1), headerResponse.getLastHeader("Content-Type").getValue(), Long.parseLong(headerResponse.getLastHeader("Content-Length").getValue()));
} catch (ParseException var5) {
throw new SeaweedfsException("Could not parse last modified time [" + headerResponse.getLastHeader("Last-Modified").getValue() + "] to long value");
}
}
二、此时,推想下,可能是因为上传文件的时候未保存 Content-Type 导致的。那我们就去看下 saveFileByStream 上传文件这个方法,看到有重载方法
public FileHandleStatus saveFileByStream(String fileName, InputStream stream) throws IOException { return this.saveFileByStream(fileName, stream, ContentType.DEFAULT_BINARY); }
public FileHandleStatus saveFileByStream(String fileName, InputStream stream, ContentType contentType) throws IOException {
AssignFileKeyResult assignFileKeyResult = this.masterWrapper.assignFileKey(this.assignFileKeyParams);
String uploadUrl;
if (this.usingPublicUrl) {
uploadUrl = assignFileKeyResult.getPublicUrl();
} else {
uploadUrl = assignFileKeyResult.getUrl();
}
return new FileHandleStatus(assignFileKeyResult.getFid(), this.volumeWrapper.uploadFile(uploadUrl, assignFileKeyResult.getFid(), fileName, stream, this.timeToLive, contentType), uploadUrl);
}
三、于是就试了一下用重载的 saveFileByStream 方法(设置contentType的信息),那再看下 ContentType 这个类,是 final 修饰的,而且用的是 DEFAULT_BINARY,此时我们试下给 contenType重新赋值,传进去。修改 saveFileByStream 方法如下:
/** * @Description: 上传附件接口 * @Author: ma.kangkang * @Date: 2019/12/19 */ @PostMapping("/upload") @ApiOperation(value = "上传附件接口", notes = "上传附件,上传成功返回附件id") public RestResponse uploadFile(@RequestParam(name = "fileId",required = false) String fileId, @RequestParam("excelFile") MultipartFile file) throws IOException { try { if (file.isEmpty()) { return RestResponse.fail().setMsg("上传文件不能为空!"); } if (!StringUtils.isEmpty(fileId)){ return RestResponse.ok(template.updateFileByStream(fileId,file.getOriginalFilename(),file.getInputStream())); } // 新增contentType设置传参 ContentType contentType = ContentType.create("application/x-www-form-urlencoded", Consts.ISO_8859_1); return RestResponse.ok(template.saveFileByStream(file.getOriginalFilename(), file.getInputStream(),contentType)); } catch (Exception e) { logger.error("上传附件失败", e); return RestResponse.fail().setMsg("上传附件服务连接关闭"); } }
四、修改完重启项目,再去看下下载附件接口,发现不报空指针了,但是返回的文件名乱码,而且未返回文件url,那我们修改下载接口如下(1、解决文件名乱码,2、返回文件url):
/** * 获取附件的详情 * @return */ @GetMapping("/getFileInfo/{fileId}") @ApiOperation(value="公共下载附件接口",notes = "下载附件接口") @ApiImplicitParams(value = {@ApiImplicitParam(name = "fileId", value = "附件id", dataType = "String", required = true)}) public RestResponse getFileInfo(@PathVariable String fileId) throws IOException { FileHandleStatus status = template.getFileStatus(fileId); // 解决文件名乱码 String name = new String(status.getFileName().substring(8,status.getFileName().length()-1).getBytes("iso-8859-1"),"utf-8"); SeaweedResponse response = new SeaweedResponse(); if (status != null){ response.setFileId(status.getFileId()); response.setFileName(name); // 重新根据文件id 获取文件的 url response.setFilePath(template.getFileUrl(fileId)); } return RestResponse.ok(response); } 问题完美解决,搞了半天终于把问题解决,喝杯咖啡冷静下。
我是进阶的球儿,大家一起2019年的爬坑历程。感觉分享很给力的话给个赞,谢谢!!!有问题也可以下方留言或者加本人QQ:313989006 进行沟通。