SpringCloud 下 MultipartFile 序列化(JSON)出错的解决方案
在SpringCloud架构下,用户向客户端上传文件,客户端调用文件处理微服务去处理文件。
·
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[] 中读取文件并保存
/**
* 保存 byte[] 形式的文件
* @param bytesOfFile 以 byte[] 形式存储的文件
* @param fileType 文件类型
* @param saveDir 存储目录
* @return
*/
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;
}
更多推荐
已为社区贡献5条内容
所有评论(0)