Spring应用中如何通过注解实现关联ID转实体对象?
问题场景
我在Spring应用中定义了如下ProductModel实体类:
@Entity(name = "products") public class ProductModel { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String name; private String code; private boolean is_group; @ManyToOne private ProductModel group; }
前端传入的JSON数据如下:
{ "id":"50bfddf4-d5f8-11ed-afa1-0242ac120002", "name":"Phone", "group_id":"7bd886d0-d5f8-11ed-afa1-0242ac120002" }
当前我的控制器代码需要通过productRepo.findById()方法查询关联实体并赋值:
@CrossOrigin @PostMapping(value = "/product/save",produces = "application/json", consumes="application/json") void saveProduct(@RequestBody ProductModel productModel){ var group_id=productModel.getGroup_id(); if(group_id!=null && group_id.length()>0){ var group=productRepo.findById(UUID.fromString(group_id)).get(); if(group!=null){ productModel.setGroup(group); } } productRepo.save(productModel); }
请问如何通过注解或其他配置,无需使用findById()方法,直接将JSON中的group_id转换为ProductModel对象?需要提供代码示例。
解决方案
可以通过自定义Jackson反序列化器或实体类临时字段绑定两种方式实现自动转换,以下是具体代码示例:
方案一:自定义JsonDeserializer
通过自定义反序列化逻辑,在JSON转实体的过程中自动完成关联实体查询,无需在控制器中手动处理。
1. 编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.UUID; @Component public class ProductModelDeserializer extends JsonDeserializer<ProductModel> { private final ProductRepo productRepo; @Autowired public ProductModelDeserializer(ProductRepo productRepo) { this.productRepo = productRepo; } @Override public ProductModel deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode node = parser.getCodec().readTree(parser); ProductModel product = new ProductModel(); // 赋值基础字段 if (node.has("id")) { product.setId(UUID.fromString(node.get("id").asText())); } product.setName(node.get("name").asText()); if (node.has("code")) { product.setCode(node.get("code").asText()); } if (node.has("is_group")) { product.setIs_group(node.get("is_group").asBoolean()); } // 自动处理group_id关联查询 if (node.has("group_id") && !node.get("group_id").isNull()) { UUID groupId = UUID.fromString(node.get("group_id").asText()); product.setGroup(productRepo.findById(groupId).orElse(null)); } return product; } }
2. 绑定反序列化器到实体类
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import jakarta.persistence.*; import java.util.UUID; @Entity(name = "products") @JsonDeserialize(using = ProductModelDeserializer.class) // 指定自定义反序列化器 public class ProductModel { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String name; private String code; private boolean is_group; @ManyToOne private ProductModel group; // 必须添加所有字段的getter/setter,此处省略实现 public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public boolean isIs_group() { return is_group; } public void setIs_group(boolean is_group) { this.is_group = is_group; } public ProductModel getGroup() { return group; } public void setGroup(ProductModel group) { this.group = group; } }
3. 简化控制器代码
@CrossOrigin @PostMapping(value = "/product/save", produces = "application/json", consumes = "application/json") void saveProduct(@RequestBody ProductModel productModel) { productRepo.save(productModel); }
方案二:临时字段绑定+自动查询
在实体类中添加临时字段接收group_id,通过setter方法自动触发关联查询,无需额外编写反序列化器。
修改实体类
import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.UUID; @Entity(name = "products") @Component // 让Spring管理实体类,用于注入Repository public class ProductModel { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String name; private String code; private boolean is_group; @ManyToOne(fetch = FetchType.LAZY) private ProductModel group; // 临时字段,仅用于接收前端传入的group_id,不持久化到数据库 @JsonProperty("group_id") private transient UUID groupId; // 静态注入Repository,避免循环依赖问题 private static ProductRepo productRepo; @Autowired public void setProductRepo(ProductRepo productRepo) { ProductModel.productRepo = productRepo; } // 通过setter自动查询关联实体 public void setGroupId(UUID groupId) { this.groupId = groupId; if (groupId != null) { this.group = productRepo.findById(groupId).orElse(null); } } // 其他字段的getter/setter省略 public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public boolean isIs_group() { return is_group; } public void setIs_group(boolean is_group) { this.is_group = is_group; } public ProductModel getGroup() { return group; } public void setGroup(ProductModel group) { this.group = group; } }
控制器代码简化
@CrossOrigin @PostMapping(value = "/product/save", produces = "application/json", consumes = "application/json") void saveProduct(@RequestBody ProductModel productModel) { productRepo.save(productModel); }
必备基础配置
确保你的ProductRepo继承JpaRepository:
import org.springframework.data.jpa.repository.JpaRepository; import java.util.UUID; public interface ProductRepo extends JpaRepository<ProductModel, UUID> { }
内容的提问来源于stack exchange,提问作者Сэм Қыпшақ
相关产品推荐
相关产品推荐

