You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含图片字段的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();
    }
}

问题分析

  1. 语法错误:
    • ShopDto的toEntity方法缺少build()调用和闭合括号,会导致编译失败。
    • Controller的save方法参数列表末尾有多余逗号,编译报错。
  2. Multipart请求处理逻辑缺失:
    • 当前Controller仅接收ShopDto,但前端上传图片时需要通过Multipart文件传递,DTO中的byte[] image无法直接绑定上传的文件。
  3. 实体存储优化缺失:
    • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 13:05:27