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
相关产品推荐
相关产品推荐

