关于文件上传

我试图在接收 JSON 格式请求的接口中,直接用 MultipartFile 类型接收文件(字段名 image),但 Jackson 无法将 JSON 数据反序列化为 MultipartFile 这个抽象类型,因为它没有可用于实例化的构造方法(比如无参构造),就会报InvalidDefinitionException错。

后面直接用String类型接收文件了打算,毕竟最后都要传到云上。那么估计是前端处理了。

下面是原因:

MultipartFile 是 Spring 用于处理表单文件上传 (multipart/form-data 格式)的接口,而不是处理 JSON 格式的类型,两者的使用场景完全冲突:

  1. JSON 格式 :通过 @RequestBody 接收,Jackson 会把 JSON 字符串解析成 Java 对象,但 MultipartFile 是抽象接口,没有默认构造方法,也无法被 Jackson 序列化 / 反序列化;
  2. 错误场景 :
    • 我的 CreateClothingRequest DTO 中包含 MultipartFile image 字段;
    • 接口用 @RequestBody 接收 JSON 请求,Spring 试图用 Jackson 解析 JSON 中的 image 字段为 MultipartFile,但解析失败;
    • 异常日志中 "abstract types either need to be mapped to concrete types" 也明确指出:MultipartFile 是抽象类型,无法直接实例化。

简单说:JSON 格式无法传输文件,MultipartFile 也不能被 JSON 解析,你混淆了 "JSON 请求" 和 "文件上传请求" 的处理方式。

解决方案(正确的文件上传 + JSON 参数处理)

文件上传的请求格式必须是 multipart/form-data(而非 application/json),同时要调整 DTO 和接口的写法,以下是完整的正确实现:

步骤 1:修正 DTO (移除 MultipartFile,拆分参数)

如果你的请求既需要文件,又需要其他 JSON 格式的业务参数,有两种常见方案:

方案 1:表单方式(推荐,简单)

DTO 只保留非文件的业务字段,文件单独用 MultipartFile 接收:

复制代码
// CreateClothingRequest.java(仅保留业务字段)
@Data
public class CreateClothingRequest {
    private String name; // 服装名称
    private Integer type; // 服装类型
    private String style; // 风格标签
    // 其他业务字段...
    // 注意:移除 MultipartFile image 字段
}
方案 2:JSON 字符串 + 文件(适合复杂参数)

如果业务参数结构复杂,可将业务参数封装为 JSON 字符串,文件单独接收:

复制代码
// 无需修改 DTO(保留所有业务字段),接口层单独处理 JSON 字符串
步骤 2:修正接口写法(处理 multipart/form-data 格式)

接口不再用 @RequestBody,而是用 @RequestPart/@RequestParam 接收文件和参数:

方案 1 实现(表单方式)
复制代码
@RestController
@RequestMapping("/clothing")
public class ClothingController {

    // 关键:consumes 指定为 multipart/form-data,接收文件+表单参数
    @PostMapping(value = "/create", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result createClothing(
            // 接收文件(required = true 表示必传,可根据需求调整)
            @RequestPart("image") MultipartFile image,
            // 接收其他业务参数(如果参数多,也可以用 CreateClothingRequest 接收)
            @RequestParam("name") String name,
            @RequestParam("type") Integer type,
            @RequestParam("style") String style) {
        
        // 1. 处理文件上传(比如保存到本地/OSS)
        if (!image.isEmpty()) {
            String originalFilename = image.getOriginalFilename();
            // 示例:保存文件到本地
            image.transferTo(new File("/upload/" + originalFilename));
        }
        
        // 2. 处理业务参数,构建实体类
        CreateClothingRequest request = new CreateClothingRequest();
        request.setName(name);
        request.setType(type);
        request.setStyle(style);
        
        // 3. 执行业务逻辑
        // clothingService.create(request, image);
        
        return Result.success("创建服装成功");
    }
}
方案 2 实现(JSON 字符串 + 文件)

适合参数结构复杂的场景,业务参数以 JSON 字符串传递:

复制代码
@PostMapping(value = "/create", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result createClothing(
        @RequestPart("image") MultipartFile image,
        // 接收 JSON 字符串格式的业务参数
        @RequestPart("request") CreateClothingRequest request) {
    
    // 处理文件 + 业务参数
    // ...
    
    return Result.success();
}
步骤 3:客户端请求示例(PostMan / 前端)

请求格式必须是 multipart/form-data,而非 JSON:

  1. 请求头 :Content-Type: multipart/form-data(客户端会自动加,无需手动写);
  2. 请求体 :
    • 选择 form-data 格式;
    • 新增键值对:
      • 键:image,类型选 File,值选择要上传的文件;
      • 键:name,类型选 Text,值填 "短袖 T 恤";
      • 键:type,类型选 Text,值填 1;
      • 其他业务参数同理。

关键补充:为什么不能用 JSON 传文件?

JSON 是文本格式 ,只能传输字符串、数字、布尔等基础类型,无法直接传输二进制文件(比如图片、视频)。文件上传的标准方式是用 multipart/form-data 格式,它专门用于传输二进制数据 + 表单参数。

总结

  1. 核心原因 :混淆了 JSON 请求(application/json)和文件上传请求(multipart/form-data),试图用 Jackson 解析 MultipartFile 抽象类型导致失败;
  2. 关键修复 :
    • 接口改为接收 multipart/form-data 格式,移除 @RequestBody;
    • DTO 中移除 MultipartFile 字段,文件单独用 @RequestPart 接收;
    • 客户端按 form-data 格式发送文件 + 业务参数;
  3. 避坑要点 :MultipartFile 仅用于 multipart/form-data 格式的文件上传,不能和 @RequestBody 同时使用。
相关推荐
茉莉玫瑰花茶1 分钟前
GO [ 函数 ]
开发语言·后端·golang
2601_966949652 分钟前
每日自动更新股票行情:如何设计可靠的数据任务,避免重复写入和脏数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
ZealSinger8 分钟前
Go1.25容器感知GOMAXPROCS避限流
java·开发语言
打工仔折腾 AI10 分钟前
从零写一个CAD 02:实体容器、Esc取消与键盘失灵的排查
人工智能·后端·python·性能优化
茉莉玫瑰花茶23 分钟前
GO [ 类型 ]
开发语言·数据库·golang
用户83562907805123 分钟前
使用 Python 拆分和提取 PDF 页面
后端·python
用户83562907805125 分钟前
使用 Python 操作 PowerPoint 中的图片
后端·python
梅雅达编程笔记28 分钟前
02_BeautifulSoup网页数据提取
开发语言·爬虫·python·beautifulsoup·数据采集
Escalating_xu32 分钟前
【C 语言】深入理解指针(3):字符指针、数组指针、二维数组传参、函数指针与转移表
java·c语言·开发语言
ai小陈32 分钟前
深度学习CUDA OOM排查:显存占用与碎片问题实战
服务器·人工智能·python·深度学习·ai·gpu算力