在 Spring Boot 项目开发过程中,我们经常会遇到 前端传参与后端 DTO 定义不一致 的情况。 最近在项目中就踩到这样一个坑:前端传输 JSON 数据时,后端 Jackson 反序列化直接报错。
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot deserialize value of type `java.lang.String` from Array value (token `JsonToken.START_ARRAY`)
at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 4230]
(through reference chain: com.ruoyi.manage.task.domain.dto.TaskUpdateDTO["images"])从报错可以看出:
String 类型;[...])**;Array 转换成 String,触发了 MismatchedInputException。前端传递的数据如下(简化版):
{
"images": ["https://********.png"]
}由于后端的 DTO 字段定义为 String 类型,而前端传了数组,Jackson 无法自动匹配,从而抛出异常。
总结下来,产生这个问题的根本原因有两点:
String,但前端传了 Array;根据业务场景,有三种常见解决思路:
如果业务允许上传多张图片,后端 DTO 应该改成集合类型:
@Data
public class TaskUpdateDTO {
private List<String> images; // 支持多张图片
}对应前端传参:
"images": ["https://xx.jpg", "https://yy.jpg"]这样 Jackson 会自动完成映射,最为推荐。
如果业务只允许单张图片,可以把字段定义为单个 String,并保持字段名和前端一致:
@Data
public class TaskUpdateDTO {
private String image; // 单数,和前端一致
}对应前端 JSON:
"image": "https://xx.jpg"如果需要兼容两种情况(既可能是字符串,也可能是数组),可以自定义反序列化器:
@Data
public class TaskUpdateDTO {
@JsonDeserialize(using = ImageDeserializer.class)
private List<String> images; // 兼容单图 / 多图
}自定义反序列化器:
public class ImageDeserializer extends JsonDeserializer<List<String>> {
@Override
public List<String> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
JsonToken token = p.currentToken();
if (token == JsonToken.START_ARRAY) {
return ctxt.readValue(p, new TypeReference<List<String>>() {});
} else if (token == JsonToken.VALUE_STRING) {
return List.of(p.getValueAsString());
}
return Collections.emptyList();
}
}这样,无论前端传:
"images": "https://xx.jpg"还是:
"images": ["https://xx.jpg", "https://yy.jpg"]后端都能正确解析为 List<String>。
String image;List<String> images;根本原则是:保持前后端字段名和字段类型一致,否则 Jackson 在反序列化时必然报错
👉 通过这次问题,也提醒我们在接口设计阶段,应尽早约定好字段类型和字段名,避免前后端各自随意定义,导致序列化和反序列化失败。