You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot+OpenAPI接收多文件报错:无法反序列化List<Resource>

解决SpringBoot + OpenAPI多文件上传时List反序列化错误

问题根源

你碰到的JSON解析错误,本质是两个问题导致:

  1. Spring对文件上传的原生支持是MultipartFile类型(它本身实现了Resource接口),但默认不支持将multipart/form-data中的文件直接反序列化为List<Resource>。
  2. 如果OpenAPI生成的Controller用@RequestBody接收multipart请求,Spring会错误地把请求内容当作JSON解析,直接触发序列化失败。

解决方案

方案一:调整OpenAPI生成配置,改用List(优先推荐)

这是最省心的解决方式,完全利用Spring原生的文件上传能力:

  1. 修改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>
    
  2. 重新生成代码后,接口参数会变为List<MultipartFile> attachedFiles,Spring会自动完成multipart文件的绑定,不需要额外配置。

方案二:自定义Jackson反序列化器适配List

如果业务必须保留List<Resource>类型,可以通过自定义反序列化器实现转换:

  1. 编写反序列化器:
    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);
                }
            }
        }
    }
    
  2. 注册反序列化器:
    在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;
        }
    }
    
  3. 关联反序列化器到模型字段:
    如果OpenAPI生成的模型类中attachedFiles字段没有自动绑定反序列化器,手动添加@JsonDeserialize注解:
    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方法
    }
    
    提示:如果代码是自动生成的,建议修改OpenAPI的模板文件来持久化这个注解,避免每次生成后手动修改。

额外注意

multipart/form-data类型的请求绝对不能用@RequestBody接收,必须用@RequestPart或@RequestParam,通过OpenAPI生成配置中的useRequestPart=true可以自动生成正确的注解。

内容的提问来源于stack exchange,提问作者antho.dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:28:15