Spring Boot中如何在POST请求JSON仅传递manufacturerId外键?
问题描述
我正在开发一个在线鞋店,为商品模块创建REST控制器,当前测试POST请求时,商品与厂商通过manufacturerId关联(商品表goods通过ManufacturerId字段关联厂商表manufacturers的id字段)。目前我需要在JSON中传入厂商的完整信息,但认为这并非最佳实践。
商品实体类
@Entity @Table(name = "goods") public class Good { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) //@JsonIgnore private int id; @Column(name = "Title") private String title; // @Enumerated(EnumType.STRING) // @Column(name = "sex") // private sexType sexType; @Column(name = "sex") private String sex; /** * proved and it actually works! */ //@JsonManagedReference @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE}) @JoinColumn(name = "ManufacturerId") //@JsonIgnoreProperties Manufacturer manufacturer; //Many goods can refer to one manufacturer @JsonManagedReference @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE}, mappedBy = "good")//Uni-directional reference to size array List<Size> sizes; }
厂商实体类
@Entity @Table(name = "manufacturers") public class Manufacturer { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(name = "ManufacturerName") private String manufacturerName; @Column(name = "Address") private String address; @Column(name = "Telephone") private String telephone; //@JsonBackReference @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH, CascadeType.MERGE}, mappedBy = "manufacturer") @JsonIgnore private List<Good> goods; }
当前POST请求JSON示例
{ "title": "Model", "sex": "CHILD", "manufacturer": { "id": 1, "manufacturerName": "Ralf", "address": "Moscow", "telephone": "9-999-999-99-99" }, "sizes": [ { "size": 37, "quantity": 5 }, { "size": 39, "quantity": 4 } ] }
疑问
- 如何仅传递
manufacturerId来创建商品? - 担心使用
@JsonIgnore注解后,无法获取厂商的额外信息,该怎么处理?
解决方案
一、仅传递manufacturerId创建商品
推荐使用**DTO(数据传输对象)**方案,这是REST接口开发的最佳实践,能清晰区分输入输出数据结构,避免直接暴露实体类。
步骤1:创建输入DTO
定义专门用于接收创建请求的DTO,只保留必要字段,厂商仅用manufacturerId表示:
public class GoodCreateDTO { private String title; private String sex; private Integer manufacturerId; private List<SizeCreateDTO> sizes; // Getter、Setter方法 } public class SizeCreateDTO { private Integer size; private Integer quantity; // Getter、Setter方法 }
步骤2:控制器中处理DTO转换
在REST控制器接收DTO,手动转换为实体类并完成关联查询:
@PostMapping("/goods") public ResponseEntity<GoodResponseDTO> createGood(@RequestBody GoodCreateDTO dto) { // 从数据库查询对应ID的厂商,不存在则抛出异常 Manufacturer manufacturer = manufacturerRepository.findById(dto.getManufacturerId()) .orElseThrow(() -> new RuntimeException("指定ID的厂商不存在")); // 转换为Good实体 Good good = new Good(); good.setTitle(dto.getTitle()); good.setSex(dto.getSex()); good.setManufacturer(manufacturer); // 处理尺码列表转换 List<Size> sizes = dto.getSizes().stream() .map(sizeDto -> { Size size = new Size(); size.setSize(sizeDto.getSize()); size.setQuantity(sizeDto.getQuantity()); size.setGood(good); return size; }) .collect(Collectors.toList()); good.setSizes(sizes); // 保存商品 Good savedGood = goodRepository.save(good); // 转换为响应DTO返回(下文会说明) return ResponseEntity.ok(convertToResponseDTO(savedGood)); }
简化后的POST请求JSON
{ "title": "Model", "sex": "CHILD", "manufacturerId": 1, "sizes": [ { "size": 37, "quantity": 5 }, { "size": 39, "quantity": 4 } ] }
二、解决@JsonIgnore导致无法获取厂商信息的问题
当前你在Manufacturer的goods字段上加@JsonIgnore,只会忽略厂商关联的商品列表,不会影响厂商自身信息的序列化。如果是担心返回商品时无法带出厂商信息,可通过以下方式处理:
方案1:使用响应DTO返回完整信息
创建专门的响应DTO,包含商品和厂商的完整信息:
public class GoodResponseDTO { private Integer id; private String title; private String sex; private ManufacturerResponseDTO manufacturer; private List<SizeResponseDTO> sizes; // Getter、Setter方法 } public class ManufacturerResponseDTO { private Integer id; private String manufacturerName; private String address; private String telephone; // Getter、Setter方法 } public class SizeResponseDTO { private Integer size; private Integer quantity; // Getter、Setter方法 }
在控制器中实现实体到DTO的转换(可使用MapStruct等工具简化转换逻辑),返回时就能展示完整的厂商信息,同时避免实体循环引用问题。
方案2:调整实体序列化注解
如果不想用DTO,可调整实体类的注解,确保序列化时能返回厂商信息:
- 保留
Manufacturer类的所有字段,goods字段继续用@JsonIgnore避免循环引用; Good类的manufacturer字段不要加@JsonIgnore,这样返回商品时会自动带出关联的厂商完整信息。
内容的提问来源于stack exchange,提问作者velovatik
相关产品推荐
相关产品推荐

