当前位置: 首页 > java >正文

Web-图片上传出现的错误

前后端数据格式的交互方式不匹配


​问题根源​

  1. ​后端期望的格式​​(LostItemController.java):

    • 使用 @RequestPart LostItemRequestDTO request 接收 ​​JSON 对象​​(自动反序列化)
    • 使用 @RequestPart MultipartFile image 接收 ​​文件​
    • 要求 Content-Type: multipart/form-data
  2. ​前端实际发送的格式​​:

    • 将 JSON 数据以字符串形式放在 request 字段(formData.append('request', JSON.stringify(requestData))
    • 后端无法自动反序列化 request 字段中的 JSON 字符串,导致 ​​415 错误​

解决方案​

​方案1:修改前端 - 直接发送对象而非 JSON 字符串​

前端不需要手动 JSON.stringify,直接让 FormData 按字段拆分

async submitForm() {const formData = new FormData();// 直接添加字段(不要包裹成 JSON 字符串)formData.append('category', this.formData.category);formData.append('description', this.formData.description);formData.append('lostLocation', this.formData.lostLocation);formData.append('lostTime', new Date(this.formData.lostTime).toISOString());// 添加图片if (this.formData.image) {formData.append('image', this.formData.image);}try {const response = await fetch('/api/lost', {method: 'POST',body: formData, // 不要手动设置 Content-Type!});// 处理响应...} catch (error) {alert('提交失败: ' + error.message);}
}

方案2:修改后端 - 手动解析 JSON 字符串​

如果必须保持前端发送 request 字段,后端需调整:

@PostMapping(value = "/lost", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result add(@RequestPart String request,  // 改为接收字符串@RequestPart(required = false) MultipartFile image
) {// 手动解析 JSONLostItemRequestDTO requestData = new ObjectMapper().readValue(request, LostItemRequestDTO.class);// 后续逻辑...
}
 

后端无法反序列化前端发送的 LostItemRequestDTO 对象​​,具体错误为:

Cannot construct instance of `com.text.pojo.LostItemRequestDTO` 
(no Creators, like default constructor, exist)

确保前后端字段名严格一致(尤其是 image

问题根源​

  1. ​后端问题​​:

    • LostItemRequestDTO 类缺少 ​​默认构造函数​​ 或 ​​Jackson 反序列化所需的注解​​。
    • Spring 无法将前端传来的 JSON 数据自动转换为 LostItemRequestDTO 对象。
  2. ​前端问题​​:

    • 当前前端发送的是 ​FormData​,但后端期望的是 ​multipart/form-data 中的 JSON 对象​​(@RequestPart LostItemRequestDTO request

解决办法:

修复后端 DTO 类(推荐)​

在 LostItemRequestDTO 中添加 ​​无参构造函数​​ 和 ​​Setter 方法​

package com.text.pojo;public class LostItemRequestDTO {private String category;private String description;private String lostLocation;private String lostTime;// 1. 必须添加无参构造函数public LostItemRequestDTO() {}// 2. 必须提供所有字段的 getter/setterpublic String getCategory() { return category; }public void setCategory(String category) { this.category = category; }// 其他字段的 getter/setter...
}

方案2:修改后端控制器(手动解析 JSON)​

如果无法修改 DTO,可以手动解析 JSON:

@PostMapping(value = "/lost", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result add(@RequestPart String request,  // 改为接收字符串@RequestPart(required = false) MultipartFile image
) {// 手动解析 JSONObjectMapper objectMapper = new ObjectMapper();LostItemRequestDTO requestData = objectMapper.readValue(request, LostItemRequestDTO.class);// 后续逻辑...
}

方案3:调整前端请求格式​

如果后端坚持用 @RequestPart LostItemRequestDTO request,前端需要 ​​按字段拆分 FormData​​(不推荐,但可行):

const formData = new FormData();
formData.append('category', this.formData.category);
formData.append('description', this.formData.description);
formData.append('lostLocation', this.formData.lostLocation);
formData.append('lostTime', this.formData.lostTime);
formData.append('image', this.formData.image);

问题根源​

  1. LocalDateTime 反序列化失败​​:

    • 前端发送的 lostTime 是字符串(如 "2025-06-05T20:06:13"),但后端无法自动将其转换为 LocalDateTime
    • 需要为 LocalDateTime 配置自定义反序列化器。
  2. ​DTO 构造函数冲突​​:

    • 虽然提供了无参构造函数,但还存在全参构造函数,可能导致 Jackson 混淆。

​解决方案​

​1. 修复 DTO 类​

package com.text.pojo;import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import java.time.LocalDateTime;public class LostItemRequestDTO {private String category;private String description;private String lostLocation;@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") // 指定日期格式@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 使用反序列化器private LocalDateTime lostTime;// 只保留无参构造函数public LostItemRequestDTO() {}// 移除全参构造函数(避免干扰 Jackson)// getters/setters...
}
2. 修改前端时间格式​

确保前端发送的时间字符串格式与 @JsonFormat 一致:

// 前端代码(格式化时间)
const requestData = {category: this.formData.category,description: this.formData.description,lostLocation: this.formData.lostLocation,lostTime: new Date(this.formData.lostTime).toISOString().slice(0, 19) // 格式:YYYY-MM-DDTHH:mm:ss
};formData.append('request', JSON.stringify(requestData));
  1. jackson 的默认行为​​:

    • 优先尝试用无参构造函数 + setter(成功)
    • ​但如果类中只有全参构造函数​​(没有无参构造),Jackson 会尝试用它,此时必须满足:
      • 参数名称 ​​严格匹配​​ JSON 字段名
      • 或使用 @JsonProperty 标注参数
  2. ​您的实际错误​​:

    • 虽然提供了无参构造函数,但全参构造函数的存在 ​​干扰了 Jackson 的决策​​(尤其在高版本 Jackson 中)
    • 更关键的是:LocalDateTime 字段没有配置反序列化规则(主因)
http://www.xdnf.cn/news/12196.html

相关文章:

  • 视频汇聚平台EasyCVR“明厨亮灶”方案筑牢旅游景区餐饮安全品质防线
  • 【HTML】HTML 与 CSS 基础教程
  • Profinet转CAN网关借助特定配置软件完成子站配置任务
  • Spring 框架之IOC容器加载重要组件
  • label-studio的使用教程(导入本地路径)
  • CppCon 2015 学习:Comparison is not simple, but it can be simpler.
  • SQL进阶之旅 Day 16:特定数据库引擎高级特性
  • Maven的生命周期
  • 【QT】显示类控件
  • 2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题
  • 华硕电脑,全新的超频方式,无需进入BIOS
  • PostgreSQL 技术峰会,为您打造深度交流优质平台
  • 神经网络-Day45
  • 第二十四章 流程控制_ if分支
  • day38 6月5号
  • Tensorrt python api 10.11.0笔记
  • 【新品解读】一板多能,AXRF49 定义新一代 RFSoC FPGA 开发平台
  • Devops系列---python基础篇二
  • 提示词指南 --- 提示词的基本结构
  • 51单片机基础部分——独立按键检测
  • 从零发布一个 Vue 3 Button 组件到 npm(基于 Vite)
  • 【推荐算法】WideDeep推荐模型:融合记忆与泛化的智能推荐引擎
  • Oracle杀进程注意事项
  • 力扣100题之128. 最长连续序列
  • 探秘 MyBatis:开启你的数据库操作「智能之旅」
  • 基于Qt的app开发第十三天
  • 【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析
  • 服务器中CC攻击的特点有哪些?
  • 全面解析网络端口:概念、分类与安全应用
  • Windows 10 IoT 系统深度定制指南:从环境搭建到工业部署