含图片字段的Shop实体请求无法发送,咨询是否需单独创建图片实体?
问题描述
无法发送POST请求,我的Shop实体包含name_shop、description和image(byte[]类型)字段,已编写对应的ShopDto、Controller、Service等代码。请问是否需要单独创建图片实体,或者如何使用包含上述字段的单个实体来成功发送请求?
现有代码
实体类(Shop.java)
@Data @SuperBuilder @AllArgsConstructor @NoArgsConstructor @Entity public class Shop{ @Id @GeneratedValue private Integer id; private String name_shop; private String description; private byte[] image; }
DTO类(ShopDto.java)
@Getter @Setter @AllArgsConstructor @Builder public class ShopDto { private Integer id; @NotNull(message = "Le nom ne doit pas être null") @NotEmpty(message = "le nom ne doit pas être vide") private String name_shop; @NotNull(message = "La description ne doit pas être null") @NotEmpty(message = "La description ne doit pas être vide") private String description; private byte[] image; public static ShopDto fromEntity(Shop shop) { return ShopDto.builder() .id(shop.getId()) .name_shop(shop.getName_shop()) .description(shop.getDescription()) .image(shop.getImage()) .build(); } public static Shop toEntity(ShopDto shop) { return Shop.builder() .id(shop.getId()) .name_shop(shop.getName_shop()) .description(shop.getDescription()) .image(shop.getImage()); // 语法错误:缺少闭合括号和build()调用 } }
控制器(ShopController.java)
@RestController @RequestMapping("/shop") @RequiredArgsConstructor public class ShopController { private final ShopService shopService; @PreAuthorize("hasAnyRole('ROLE_ADMIN')") @PostMapping(value = "/saveShop",consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<Integer> save( @RequestPart("shopDto") ShopDto shopDto, ) { // 语法错误:参数列表末尾多余逗号 return ResponseEntity.ok(shopService.save(shopDto)); } }
仓库接口(ShopRepository.java)
public interface ShopRepository extends JpaRepository<Shop, Integer> { }
服务接口(ShopService.java)
public interface ShopService extends AbstractService<ShopDto>{ }
抽象服务接口(AbstractService.java)
public interface AbstractService<T>{ Integer save(T dto); }
服务实现类(ShopServiceImpl.java)
@Service @RequiredArgsConstructor public class ShopServiceImpl implements ShopService { private final ShopRepository shopRepository; private final ObjectsValidator<ShopDto> validator; @Override public Integer save(ShopDto dto) { validator.validate(dto); Shop shop = ShopDto.toEntity(dto); return shopRepository.save(shop).getId(); } }
问题分析
- 语法错误:
- ShopDto的
toEntity方法缺少build()调用和闭合括号,会导致编译失败。 - Controller的
save方法参数列表末尾有多余逗号,编译报错。
- ShopDto的
- Multipart请求处理逻辑缺失:
- 当前Controller仅接收
ShopDto,但前端上传图片时需要通过Multipart文件传递,DTO中的byte[] image无法直接绑定上传的文件。
- 当前Controller仅接收
- 实体存储优化缺失:
byte[]类型字段未标注@Lob,部分数据库可能无法正确识别为大对象存储,导致数据截断。
解决方案
方案一:使用单个实体完成请求(无需单独创建图片实体)
适合单店铺单图片的简单场景,只需修复现有代码并调整请求处理逻辑:
1. 修复语法错误
- 修正ShopDto的
toEntity方法:
public static Shop toEntity(ShopDto shop) { return Shop.builder() .id(shop.getId()) .name_shop(shop.getName_shop()) .description(shop.getDescription()) .image(shop.getImage()) .build(); }
- 修正Controller的
save方法参数列表:
public ResponseEntity<Integer> save( @RequestPart("shopDto") ShopDto shopDto, @RequestPart(value = "image", required = false) MultipartFile image) throws IOException {
2. 调整Controller接收并转换图片
在Controller中单独接收图片文件,转换为byte[]后设置到DTO:
@PreAuthorize("hasAnyRole('ROLE_ADMIN')") @PostMapping(value = "/saveShop", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<Integer> save( @RequestPart("shopDto") ShopDto shopDto, @RequestPart(value = "image", required = false) MultipartFile image) throws IOException { if (image != null && !image.isEmpty()) { shopDto.setImage(image.getBytes()); } return ResponseEntity.ok(shopService.save(shopDto)); }
3. 优化实体存储注解
为Shop实体的image字段添加@Lob注解,明确大对象存储:
@Lob private byte[] image;
前端请求示例(FormData)
前端需用FormData构造请求,示例:
const formData = new FormData(); // 序列化ShopDto为JSON字符串 formData.append('shopDto', new Blob([JSON.stringify({ name_shop: "我的店铺", description: "优质商品店铺" })], {type: 'application/json'})); // 添加图片文件 formData.append('image', document.getElementById('imageInput').files[0]); // 发送请求 fetch('/shop/saveShop', { method: 'POST', body: formData, headers: { 'Authorization': 'Bearer ' + token // 若需认证则添加 } });
方案二:单独创建图片实体(适合复杂场景)
如果图片需要复用、存储额外元数据(如文件名、格式)或支持多图,建议单独创建图片实体:
1. 创建ShopImage实体
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Builder public class ShopImage { @Id @GeneratedValue private Integer id; private String fileName; private String contentType; private Long fileSize; @Lob private byte[] data; @ManyToOne @JoinColumn(name = "shop_id") private Shop shop; }
2. 修改Shop实体
移除原byte[] image字段,添加关联关系:
@Data @SuperBuilder @AllArgsConstructor @NoArgsConstructor @Entity public class Shop{ @Id @GeneratedValue private Integer id; private String name_shop; private String description; // 一对一关联,若支持多图可改为@OneToMany @OneToOne(mappedBy = "shop", cascade = CascadeType.ALL, orphanRemoval = true) private ShopImage image; }
3. 调整DTO与业务逻辑
创建ShopImageDto,在Controller中分别接收ShopDto和图片文件,映射为Shop和ShopImage实体并关联保存。
总结
- 简单单图场景选方案一,修复语法错误+调整Multipart请求处理即可快速解决问题。
- 复杂场景(多图、图片复用、元数据存储)选方案二,提升代码扩展性和可维护性。
内容的提问来源于stack exchange,提问作者tony
相关产品推荐
相关产品推荐

