文章目录
Spring中的MultipartFile
为什么要使用MultipartFile
在进行业务开发过程中,有时会需要用户上传图片、文档、视频等文件到表单,并向后端发送Post请求。
在SpringBoot中,就需要需要通过MultipartFile
用来接收前端表单中上传的文件,得益于java注解,可以非常容易的定义接收的参数为MultipartFile
。
public interface TestService {
@RequestMapping("/your/url")
RespDTO<ResponseClass> uploadFile(
@RequestParam String authId,
@RequestPart(required = false) MultipartFile multipartFile
);
}
MultipartFile
转File
在接收到前端表单中上传的文件后,为了在后端方便进行处理,往往会先把MultipartFile
转换成File
再进行后续操作。
public static File convertMultipartFileToFile(MultipartFile multipartFile) throws IOException {
String filename = multipartFile.getOriginalFilename();
if (filename == null) {
throw new IllegalStateException("MultipartFile's original name is NULL!");
}
Path tempFile = Files.createTempFile("", filename);
multipartFile.transferTo(tempFile);
return tempFile.toFile();
}
在Spring Cloud环境下Jackson序列化器报错
当在Spring Cloud跨服务传递MultipartFile
时,会出现序列化错误,具体报错信息如下:
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: java.util.LinkedHashMap["imageFile"]->org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])
具体含义为:在试图将包含MultipartFile
对象的实体进行JSON序列化时发生的,而MultipartFile
内部的inputStream
关联到了FileInputStream
,进一步关联到了FileDescriptor
对象,这些类型在默认情况下无法被Jackson自动序列化。
解决方案一
客户端接收到MultipartFile
文件后通过MultipartFile
的getBytes()
方法转为byte[]
数组,再通过Base64
工具类把byte[]
数组转为Base64字符串,并发送给另一个服务
另一个服务收到Base64
字符串时,再用Base64
工具类把字符串转为byte[]
数组,之后把byte[]
作为输入流,从中读取数据,写入输出流,解决报错。
解决方案二
Spring Boot中的请求注解提供了对应的属性用于规定接收的MulitipartFile
类型:
public interface TestService {
@PostMapping(value = "/your/url", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
RespDTO<ResponseClass> uploadFile(
@RequestParam String authId,
@RequestPart(required = false) MultipartFile multipartFile
);
}
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
:表明该方法期望接收的数据类型是multipart/form-data
。这是典型的文件上传请求所使用的Content-Type,因为通过HTML表单上传文件时,浏览器会以这种方式编码数据,允许同时传输文本字段和文件内容。
produces = MediaType.APPLICATION_JSON_VALUE
:声明该方法在处理请求完成后,会生成一个Content-Type为application/json
的响应。这意味着方法的返回值应当是一个可以被转换为JSON格式的对象。
在这种场景下,如果你在处理文件上传后,试图直接返回包含MultipartFile
或其内部不可JSON序列化组件的对象,就会触发前面讨论过的序列化错误。正确的方式应该是:
- 将上传的文件保存至服务器或第三方存储服务。
- 创建一个自定义响应对象,其中包含上传成功后需要返回给客户端的文件相关信息(如文件ID、URL、状态等)。
- 返回这个自定义响应对象,它会被自动转换为JSON格式并发送给客户端。