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

Spring中FormData嵌套List映射DTO问题:含MultipartFile场景

问题分析

FormData无法直接传递JavaScript数组对象,当你直接append数组时,它会被强制转换为字符串"[object Object]"。Spring的@ModelAttribute解析到这个字符串后,会调用PhoneNumber中接受String参数的构造方法,导致phNo被赋值为该字符串,而id因无对应参数值保持为null。


解决方案

方案1:前端按Spring数据绑定规则构造参数

Spring对集合类型的属性绑定,支持索引式参数命名,格式为集合属性名[索引].子属性名。通过这种方式,Spring可以自动将参数映射到集合内的对象属性中。

前端代码修改

$(document).ready(function() {
    $("#submit").click(function() {
        let fdata = new FormData();
        fdata.append("name", "hello");
        fdata.append("image", $("#contactimage")[0].files[0]);
        // 为List中的每个PhoneNumber对象逐个绑定属性
        fdata.append("phNos[0].id", 1);
        fdata.append("phNos[0].phNo", "12345");
        // 多个手机号可继续追加:phNos[1].id、phNos[1].phNo...

        fetch("/save/c", {
            body: fdata,
            method: "post"
        }).then((response) => {
            // 响应处理逻辑
        });
    });
});

后端PhoneNumber类修改

移除自定义的单参数构造方法,添加无参构造(Spring需要通过无参构造创建对象后,再通过setter注入属性):

@Data
@AllArgsConstructor
@NoArgsConstructor // 必须添加无参构造
public class PhoneNumber {
    private Integer id;
    private String phNo;
}

方案2:后端自定义转换器处理JSON格式参数

如果前端不想调整参数构造方式,可以将数组转为JSON字符串传递,后端通过自定义转换器完成JSON到List<PhoneNumber>的转换。

前端代码修改

将数组转为JSON字符串后append到FormData:

$(document).ready(function() {
    $("#submit").click(function() {
        let fdata = new FormData();
        fdata.append("name", "hello");
        fdata.append("image", $("#contactimage")[0].files[0]);
        // 将手机号数组转为JSON字符串
        fdata.append("phNos", JSON.stringify([{id:1,phNo:"12345"}]));

        fetch("/save/c", {
            body: fdata,
            method: "post"
        }).then((response) => {
            // 响应处理逻辑
        });
    });
});

后端添加数据绑定转换器

在Controller中通过@InitBinder注册自定义属性编辑器,处理JSON字符串到集合的转换:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestController;
import java.beans.PropertyEditorSupport;
import java.util.List;

@RestController
public class DemoRestController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(List.class, "phNos", new PropertyEditorSupport() {
            private final ObjectMapper objectMapper = new ObjectMapper();

            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                try {
                    // 将JSON字符串转为List<PhoneNumber>
                    List<PhoneNumber> phoneNumbers = objectMapper.readValue(
                            text,
                            new TypeReference<List<PhoneNumber>>() {}
                    );
                    setValue(phoneNumbers);
                } catch (JsonProcessingException e) {
                    throw new IllegalArgumentException("手机号列表格式错误", e);
                }
            }
        });
    }

    @PostMapping("/save/c")
    public void saveContact(@ModelAttribute ContactDetail contactDetail) {
        System.out.println(contactDetail);
    }
}

同时确保PhoneNumber类添加@NoArgsConstructor,保证Jackson能正常反序列化对象。


内容的提问来源于stack exchange,提问作者Mr Anonymous

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:20:49