FormData 不会把 JavaScript 对象数组自动序列化为 Java List。直接 append 对象时,常见结果是字符串 [object Object];即使先 JSON.stringify,后端也必须按同一契约反序列化,不能指望普通表单绑定自动解析这段 JSON。
先明确字段传的是什么
假设列表是:
const items = [{ name: "示例 A", count: 2 }, { name: "示例 B", count: 1 }];
const form = new FormData();
form.append("itemsJson", JSON.stringify(items));
itemsJson 是一个包含 JSON 数组文本的表单字段,不是多个 JavaBean 字段。FormData.append 文档说明非字符串、非 Blob 的值会转成字符串,这也是直接传对象产生问题的原因。
提交时不要手动写不带 boundary 的 multipart/form-data 请求头,由浏览器构造:
async function submitItems(items) {
const form = new FormData();
form.append("itemsJson", JSON.stringify(items));
const response = await fetch("/items", {
method: "POST",
body: form
});
if (!response.ok) throw new Error("提交失败");
return response.json();
}
函数只是说明请求契约,项目仍需按自己的认证、CSRF 和错误协议补齐调用条件。
Spring 端显式读取这个 JSON 字段
旧代码使用过 Fastjson.parseArray。下面用 Spring Boot 常见的 Jackson 组件表达同一件事,适用于有 Jackson 和 Spring MVC 的工程:
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ItemsController {
private final ObjectMapper mapper;
public ItemsController(ObjectMapper mapper) {
this.mapper = mapper;
}
@PostMapping("/items")
public List<Item> items(@RequestParam("itemsJson") String itemsJson)
throws IOException {
List<Item> items = mapper.readValue(
itemsJson, new TypeReference<List<Item>>() {});
if (items == null || items.size() > 100) {
throw new IllegalArgumentException("列表大小不符合要求");
}
for (Item item : items) {
if (item == null || item.name == null ||
item.name.trim().isEmpty() || item.count <= 0) {
throw new IllegalArgumentException("条目不符合要求");
}
}
return items;
}
public static class Item {
public String name;
public int count;
}
}
示例返回解析结果供观察,不包含数据库写入。实际应用应限制请求和字段长度,按统一异常协议将无效 JSON 与校验失败转换为客户端错误,不直接使用未校验的数量、身份或价格。
有文件和没有文件时可以选不同协议
没有文件时,直接 application/json 搭配 @RequestBody 往往更简单。有文件时,也可使用 application/json 的 Blob part,后端用 @RequestPart 交给 JSON 转换器;这与本文的“字符串字段再显式解析”是两套契约,前后端应选择同一套。Spring MVC multipart 说明
第一次成功、第二次失败时,还要检查是否复用了 FormData 并重复 append,详见重复表单字段与 JSON 错误。