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

Jea*_*ean 7 java rest spring jpa

我正在使用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();

    ...
}
Run Code Online (Sandbox Code Playgroud)

该JPA存储库Product定义为:

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findAll();
}
Run Code Online (Sandbox Code Playgroud)

在我的控制器中我有:

@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;
}
Run Code Online (Sandbox Code Playgroud)

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

$ curl localhost:8080/all-products
Run Code Online (Sandbox Code Playgroud)

我得到一个递归输出由于表之间的关系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,...
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Xeo*_*eon 12

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

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

您必须使用视图或只是跳过它.

  1. 使用 @JsonView

  2. 将视图用作POJO返回new ProductView,其中包含产品的所有字段以及new CategoryView具有(产品)集合的引用(类别)(此时您可以结束)new ProductViewWithoutReferences,依此类推

  3. 用于@JsonIgnore一系列产品

并且作为旁注 - 如果它是a @RestController并且你正在调用"所有产品"那么返回其他东西而不是列表有点不寻常.在地图中包装响应是多余的.许多其他客户端在调用list()方法时需要一个列表.

  • @JeanValjean你只是注释了在序列化发生时应该跳过的类的字段.`@JsonIgnore private List <Product> products ...` (3认同)