1、需求
在SpringCloud架构下,用户向客户端上传文件,客户端调用文件处理微服务 去处理文件
2、问题
在客户端 和文件处理服务 间传递文件时,想直接把 MultipartFile 转为 json,但出现异常。
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])
分析:客户端接收到的是 MultipartFile 文件;要把文件传给文件处理微服务 ,但直接把 MultipartFile 传给文件服务是不行的。 MultipartFile 不能序列化(或者比较麻烦);
有人说在实体类上加注解,忽略掉MultipartFile属性;@JSONField(serialize = false) ,但是我的实体类没有 MultipartFile 属性。
经过一番查找,找到了一个合适的解决方案。
3、解决方案
3.1、原理图
-
客户端接收到 MultipartFile 文件 -
通过 MultipartFile 的 getBytes() 方法转为 byte[] 数组 -
通过 Base64 工具类把 byte[] 数组转为 Base64字符串 ,并发送给 文件处理服务 -
文件处理服务收到 Base64字符串时,再用 Base64 工具类把 字符串转为 byte[] 数组 -
把 byte[] 作为输入流,从中读取数据,写入输出流,完成文件的存储
3.2、实现步骤
1)MultipartFile 转 byte[]
客户端接收到客户上传的MultipartFile文件
@PostMapping("/add")
public String add(
@RequestParam("file") MultipartFile file
) {
byte[] bytes = file.getBytes();
String fileType = file.getOriginalFilename()...
}
2)byte[] 转 Base64 字符串
工具类 org.apache.tomcat.util.codec.binary.Base64 ;
byte[] 转为字符串后,可以发送给 文件处理服务 ,同时把文件类型也一起发送;因为从 byte[] 中解析文件类型比较麻烦
String bytesStr = Base64.encodeBase64String(bytes);
3)Base64 字符串 转 byte[]
文件处理服务 收到 字符串后,再转为 byte[]
byte[] bytes = Base64.decodeBase64(bytesStr);
4)从 byte[] 中读取文件并保存
public static String saveFileByBytes(
byte[] bytesOfFile,
String fileType,
String saveDir){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
String fileName = "";
try {
bis = new BufferedInputStream(new ByteArrayInputStream(bytesOfFile));
fileName = SnowflakeUtil.getInstance().nextId() + "." + fileType;
bos = new BufferedOutputStream(new FileOutputStream(new File(saveDir, fileName)));
int readLen;
byte[] buf = new byte[8192];
while ((readLen = bis.read(buf)) > -1) {
bos.write(buf, 0, readLen);
}
} catch (IOException e) {
e.printStackTrace();
log.info("文件存储异常!");
return "_err";
} finally {
try {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return fileName;
}
|