当前位置: 代码迷 >> java >> REST 控制器中具有一对多关系的实体的递归 JSON 视图
  详细解决方案

REST 控制器中具有一对多关系的实体的递归 JSON 视图

热度:101   发布时间:2023-07-27 09:36:03.0

我正在使用 SpringBoot 和 JPA 来构建 REST 接口。

现在,我为从数据库中提取的产品列表返回了一个奇怪的 JSON。 假设我有:

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "categoryId", nullable = false, updatable = false)
    private Category category;

    ...
}

@Entity
public class Category implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "category", cascade = CascadeType.DETACH)
    @OrderBy("name ASC")
    private List<Product> products = Collections.emptyList();

    ...
}

对于JPA的存储库Product的定义为:

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findAll();
}

在我的控制器中,我有:

@Autowired
private ProductRepository productRepo;

@RequestMapping("/all-products", method = RequestMethod.GET)
public Map<String,Object> home() {
    Map<String,Object> model = new HashMap<String,Object>();
    model.put("products", productRepo.findAll());
    return model;
}

让我发疯的是,如果我尝试按如下方式调用此服务:

$ curl localhost:8080/all-products

由于表productcategory之间的关系,我得到递归输出,例如:

{"products":[{"id":1,"name":"Product1","category":
{"id":1,"name":"Cat1","products":[{"id":6,"name":"Product6","category":
{"id":1,"name":"Cat1","products":[{"id":6,"name":"Product6","category":
{"id":1,...

我究竟做错了什么?

你没有做错任何事(至少在代码级别它是相当概念化的) - json 序列化程序就像这样:

  1. 产品 - 序列化它,但等待 - 有一个类别字段,因此序列化程序必须序列化类别字段
  2. Category - 序列化它,但是等等 - 有一个 products 字段,所以序列化程序必须序列化列表中的每个产品
  3. 产品 - 因为您的集合包含产品和产品包含类别,所以它会无限循环,直到超时。

您必须使用视图或跳过它。

  1. 使用

  2. 使用视图作为POJO返回new ProductView有产品的各个领域,并参考(类别),以new CategoryView (你可以在此时结束),其具有的(产品)征收new ProductViewWithoutReferences ,等等

  3. 在产品集合上使用@JsonIgnore

作为旁注 - 如果它是@RestController并且您正在调用“所有产品”,那么返回除列表之外的其他内容有点不寻常。 将响应包装在地图中是多余的。 许多休息客户端在调用list()方法时需要一个列表。

我知道这有点晚了,但在这里添加它以防万一有人面临同样的问题。 这是我可以找到的另一个相关答案,其中讨论了类似的主题

在这里引用

1.6 对处理此类父/子链接具有基于注释的支持,请参阅 。

您当然可以排除已经使用大多数 JSON 处理包(jackson、gson 和 flex-json 至少支持它)的父链接的序列化,但真正的技巧是如何反序列化它(重新创建父链接),而不是只是处理序列化方面。 虽然现在听起来只是排除可能对你有用。

编辑(2012 年 4 月): 现在支持真实,因此您也可以通过这种方式解决。

添加@JsonIgnore 对我有用

@OneToMany(mappedBy = "policy")
@JsonIgnore
private List<Payment> payments;

@JeanValjean 你是最棒的

  相关解决方案