SpringBoot+OpenAPI接收多文件报错:无法反序列化List<Resource>
解决SpringBoot + OpenAPI多文件上传时List反序列化错误
问题根源
你碰到的JSON解析错误,本质是两个问题导致:
- Spring对文件上传的原生支持是
MultipartFile类型(它本身实现了Resource接口),但默认不支持将multipart/form-data中的文件直接反序列化为List<Resource>。 - 如果OpenAPI生成的Controller用
@RequestBody接收multipart请求,Spring会错误地把请求内容当作JSON解析,直接触发序列化失败。
解决方案
方案一:调整OpenAPI生成配置,改用List(优先推荐)
这是最省心的解决方式,完全利用Spring原生的文件上传能力:
- 修改OpenAPI生成插件配置,将
binary类型映射为MultipartFile,同时确保生成的Controller用@RequestPart处理参数:
以Maven插件为例,在pom.xml中配置:<plugin> <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>6.6.0</version> <!-- 替换为最新稳定版本 --> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec> <generatorName>spring</generatorName> <configOptions> <library>spring-boot</library> <!-- 将binary类型映射为Spring的MultipartFile --> <typeMappings> <typeMapping>binary=org.springframework.web.multipart.MultipartFile</typeMapping> </typeMappings> <!-- 强制生成@RequestPart注解,替代@RequestBody --> <useRequestPart>true</useRequestPart> </configOptions> </configuration> </execution> </executions> </plugin> - 重新生成代码后,接口参数会变为
List<MultipartFile> attachedFiles,Spring会自动完成multipart文件的绑定,不需要额外配置。
方案二:自定义Jackson反序列化器适配List
如果业务必须保留List<Resource>类型,可以通过自定义反序列化器实现转换:
- 编写反序列化器:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.node.POJONode; import org.springframework.core.io.Resource; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ResourceListDeserializer extends StdDeserializer<List<Resource>> { public ResourceListDeserializer() { super(List.class); } @Override public List<Resource> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); List<Resource> resources = new ArrayList<>(); if (node.isArray()) { for (JsonNode itemNode : node) { addMultipartFile(itemNode, resources); } } else if (node.isObject()) { // 兼容前端单文件未包装成数组的场景 addMultipartFile(node, resources); } return resources; } private void addMultipartFile(JsonNode node, List<Resource> resources) { if (node instanceof POJONode) { Object pojo = ((POJONode) node).getPojo(); if (pojo instanceof MultipartFile) { resources.add((MultipartFile) pojo); } } } } - 注册反序列化器:
在Spring配置类中把这个反序列化器注册到Jackson的ObjectMapper:import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.core.io.Resource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(new com.fasterxml.jackson.core.type.TypeReference<List<Resource>>() {}, new ResourceListDeserializer()); mapper.registerModule(module); return mapper; } } - 关联反序列化器到模型字段:
如果OpenAPI生成的模型类中attachedFiles字段没有自动绑定反序列化器,手动添加@JsonDeserialize注解:
提示:如果代码是自动生成的,建议修改OpenAPI的模板文件来持久化这个注解,避免每次生成后手动修改。import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.springframework.core.io.Resource; import java.util.List; public class UploadRequest { @JsonDeserialize(using = ResourceListDeserializer.class) private List<Resource> attachedFiles; // 生成getter、setter方法 }
额外注意
multipart/form-data类型的请求绝对不能用@RequestBody接收,必须用@RequestPart或@RequestParam,通过OpenAPI生成配置中的useRequestPart=true可以自动生成正确的注解。
内容的提问来源于stack exchange,提问作者antho.dev
相关产品推荐
相关产品推荐

