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

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,提问作者Сэм Қыпшақ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:37:55