Spring Boot Rest Controller中处理多Multipart文件的方法
处理Spring Boot中Form-Data格式的主表单+子表单图片请求
问题场景
我正在开发一个包含主表单与子表单的应用:主表单存储产品详情,子表单存储产品颜色详情。前端提交的API请求为form-data格式,请求体结构示例如下:
{ "raw_material_id": 1137, "extra_wip": "", "is_active": "1", "size_ratio_name_id": "45", "is_new": 0, "created_at": null, "mrp": 125, "collection": null, "hsn_code": "62113300", "is_sync": 0, "extra_fabric_programming": "", "sub_category_name": "INDOWESTERN SET", "updated_at": null, "category_name": "MENS", "is_update": 0, "name": "8642", "season": null, "comment": "", "id": 1924, "itm_no": "", "seasonID": 7, "collectionID": 3, "raw_material_colors": [ { "color_id": 123, "color_name": "test", "item_image": (binary) }, { "color_id": 456, "color_name": "test1", "item_image": (binary) } ] }
Content-Type详情:Content-Disposition: form-data,有UI截图辅助理解。
以下是我尝试的代码:
@PutMapping( value="mainitem/{id}" , consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE }) public ResponseEntity<?> user(HttpServletRequest request, @PathVariable Integer id,@RequestBody MainItem mainItem, @RequestPart MultipartFile files) { MainItem mainItem2 = mainItemrepo.findById(id).get(); mainItem2.setId(mainItem.getId()); mainItem2.setCollection(collectionRepo.collectionForMainItem(mainItem.getCollectionID())); mainItem2.setSeason(seasonRepo.seasonForMainItem(mainItem.getSeasonID())); mainItem2.setCategory_id(categoryrepo.categoryForMainItem(mainItem.getCategory_name())); mainItem2.setSub_category_id(subcategoryrepo.subCategoryForMainItem(mainItem.getSub_category_name())); mainItem2.setComment(mainItem.getComment()); mainItem2.setCreated_at(mainItem.getCreated_at()); mainItem2.setUpdated_at(mainItem.getUpdated_at()); mainItem2.setExtra_fabric_programming(mainItem.getExtra_fabric_programming()); mainItem2.setExtra_wip(mainItem.getExtra_wip()); mainItem2.setHsn_code(mainItem.getHsn_code()); mainItem2.setIs_active(mainItem.getIs_active()); mainItem2.setIs_new(mainItem.getIs_new()); mainItem2.setIs_sync(mainItem.getIs_sync()); mainItem2.setIs_update(mainItem.getIs_update()); mainItem2.setItm_no(mainItem.getItm_no()); mainItem2.setMrp(mainItem.getMrp()); mainItem2.setName(mainItem.getName()); mainItem2.setRaw_material_id(mainItem.getRaw_material_id()); mainItem2.setSize_ratio_name_id(mainItem.getSize_ratio_name_id()); mainItemrepo.save(mainItem2); //Colors for(Map<String, Object> listMap:mainItem.getRaw_material_colors()) { System.out.println(listMap.get("color_id").toString()); System.out.println(listMap.get("color_name").toString()); System.out.println(listMap.get("item_image").toString()); } return ResponseEntity.status(HttpStatus.OK) .body(new error(200, "Data Edited Successfully", "OK", request.getRequestURI())); }
解决方案
核心问题分析
当前代码存在3个关键问题:
form-data是多部分请求,不能同时用@RequestBody和@RequestPart解析- 子表单中的
item_image是MultipartFile,无法直接映射到Map<String, Object>类型 - 多图片请求未与颜色项一一对应
步骤1:调整实体类结构
创建颜色详情实体类,明确字段类型:
public class RawMaterialColor { private Integer colorId; private String colorName; private MultipartFile itemImage; // 生成getter、setter方法 }
修改MainItem类,将颜色列表字段改为强类型:
public class MainItem { // 保留原有所有字段... private List<RawMaterialColor> rawMaterialColors; // 生成getter、setter方法 }
步骤2:重构Controller方法
使用@RequestPart分别接收主表单JSON数据和多文件列表,确保颜色与图片一一对应:
@PutMapping(value = "mainitem/{id}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<?> updateMainItem(HttpServletRequest request, @PathVariable Integer id, @RequestPart("mainItem") MainItem mainItem, @RequestPart("itemImages") List<MultipartFile> itemImages) { // 1. 处理主表单数据更新 MainItem existingItem = mainItemrepo.findById(id) .orElseThrow(() -> new RuntimeException("目标产品不存在")); // 复制更新字段(可使用BeanUtils.copyProperties简化代码) existingItem.setCollection(collectionRepo.collectionForMainItem(mainItem.getCollectionID())); existingItem.setSeason(seasonRepo.seasonForMainItem(mainItem.getSeasonID())); existingItem.setCategory_id(categoryrepo.categoryForMainItem(mainItem.getCategory_name())); existingItem.setSub_category_id(subcategoryrepo.subCategoryForMainItem(mainItem.getSub_category_name())); existingItem.setComment(mainItem.getComment()); existingItem.setCreated_at(mainItem.getCreated_at()); existingItem.setUpdated_at(mainItem.getUpdated_at()); existingItem.setExtra_fabric_programming(mainItem.getExtra_fabric_programming()); existingItem.setExtra_wip(mainItem.getExtra_wip()); existingItem.setHsn_code(mainItem.getHsn_code()); existingItem.setIs_active(mainItem.getIs_active()); existingItem.setIs_new(mainItem.getIs_new()); existingItem.setIs_sync(mainItem.getIs_sync()); existingItem.setIs_update(mainItem.getIs_update()); existingItem.setItm_no(mainItem.getItm_no()); existingItem.setMrp(mainItem.getMrp()); existingItem.setName(mainItem.getName()); existingItem.setRaw_material_id(mainItem.getRaw_material_id()); existingItem.setSize_ratio_name_id(mainItem.getSize_ratio_name_id()); mainItemrepo.save(existingItem); // 2. 处理颜色与图片关联逻辑 List<RawMaterialColor> colorList = mainItem.getRawMaterialColors(); for (int i = 0; i < colorList.size(); i++) { RawMaterialColor color = colorList.get(i); MultipartFile image = itemImages.get(i); // 示例:打印信息,实际可替换为图片存储逻辑(本地/OSS等) System.out.println("颜色ID: " + color.getColorId()); System.out.println("颜色名称: " + color.getColorName()); System.out.println("图片文件名: " + image.getOriginalFilename()); } return ResponseEntity.status(HttpStatus.OK) .body(new error(200, "Data Edited Successfully", "OK", request.getRequestURI())); }
步骤3:前端请求适配
前端需要将主表单序列化为JSON Blob,与图片一起通过FormData提交,示例代码:
const formData = new FormData(); // 构造主表单数据 const mainItemData = { raw_material_id: 1137, is_active: "1", // 其他主表单字段... rawMaterialColors: [ { colorId: 123, colorName: "test" }, { colorId: 456, colorName: "test1" } ] }; // 添加主表单JSON部分 formData.append('mainItem', new Blob([JSON.stringify(mainItemData)], { type: 'application/json' })); // 添加对应图片 formData.append('itemImages', document.getElementById('img1').files[0]); formData.append('itemImages', document.getElementById('img2').files[0]); // 发送PUT请求 fetch(`/mainitem/${id}`, { method: 'PUT', body: formData });
内容的提问来源于stack exchange,提问作者Bhavik Desai
相关产品推荐
相关产品推荐

