Spring 引导 GET 方法 returns 重复值并出现 StackOverFlow 错误

Spring Boot GET method returns duplicated values with StackOverFlow error

我正在构建一个 RESTful API GET 方法,使用 Spring Boot 从数据库中获取 return 作为 JSON 的 Bill 实体。 return 不是预期的,因为它有很多重复值和 WhosebugError。

[{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":{"id":1,"date":"2022-05-20","time":"16:48:06","total":330000.0,"billDetails":[{"billMenuItemID":{"billId":1,"menuItemId":1},"bill":
//continues for eternity

休眠日志:

Hibernate: 
    select
        bill0_.bill_id as bill_id1_0_,
        bill0_.date as date2_0_,
        bill0_.time as time3_0_,
        bill0_.total as total4_0_ 
    from
        bill bill0_
Hibernate: 
    select
        billdetail0_.bill_id as bill_id1_1_0_,
        billdetail0_.menu_item_id as menu_ite2_1_0_,
        billdetail0_.bill_id as bill_id1_1_1_,
        billdetail0_.menu_item_id as menu_ite2_1_1_,
        billdetail0_.quantity as quantity3_1_1_,
        billdetail0_.subtotal as subtotal4_1_1_,
        menuitem1_.menu_item_id as menu_ite1_2_2_,
        menuitem1_.description as descript2_2_2_,
        menuitem1_.img_url as img_url3_2_2_,
        menuitem1_.name as name4_2_2_,
        menuitem1_.price as price5_2_2_,
        menuitem1_.status as status6_2_2_,
        menuitem1_.type as type7_2_2_ 
    from
        bill_detail billdetail0_ 
    inner join
        menu_item menuitem1_ 
            on billdetail0_.menu_item_id=menuitem1_.menu_item_id 
    where
        billdetail0_.bill_id=?

我怎样才能得到像这样的 return 账单:

{
  "billId": 1,
  "date": 2022-05-20,
  "time": 16:48:06,
  "total": 330000,
  "billDetails": [
    {
      "menuItem": {
        "id": 1,
        "name": Rice,
        // other attributes of MenuItem
      },
      "quantity": 2
      "subtotal": 90000
    },
    {
      "menuItem": {
        "id": 2
        "name": Wine
        // other attributes of MenuItem
      },
      "quantity": 4
      "subtotal": 240000
    }
    ]
}

这是我的 类 和相关功能

Class比尔

@Entity(name = "bill")
@Table(name = "bill")
public class Bill {

    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @Column(name = "bill_id")
    private Long id;

    private LocalDate date;
    private LocalTime time;
    private Double total;

    @OneToMany(mappedBy = "bill", cascade = CascadeType.ALL)
    private List<BillDetail> billDetails = new ArrayList<>();

Class 菜单项

@Entity
@Table(name = "menuItem",
        uniqueConstraints = {
                @UniqueConstraint(name = "menu_item_name_unique", columnNames = "name")
        }
)
public class MenuItem {

    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @Column(name = "menu_item_id")
    private Long id;
    private ItemType type;
    private String name;
    private String description;
    private String imgUrl;
    private Double price;
    private MenuItemStatus status = MenuItemStatus.ENABLED;

    @OneToMany(mappedBy = "menuItem", cascade = CascadeType.ALL)
    private List<BillDetail> billDetails = new ArrayList<>();

Class 账单详情

@Entity
@Table(name = "bill_detail")
public class BillDetail {
    @EmbeddedId
    private BillMenuItemID billMenuItemID = new BillMenuItemID();

    @ManyToOne
    @MapsId("billId")
    @JoinColumn(name = "bill_id")
    private Bill bill;

    @ManyToOne
    @MapsId("menuItemId")
    @JoinColumn(name = "menu_item_id")
    private MenuItem menuItem;

    @Column
    private Long quantity;

    @Column
    private Double subtotal;

GET 方法

@GetMapping
    public List<Bill> getMenuItems() {
        return billService.getBills();
    }

public List<Bill> getBills() {
        return billRepository.findAll();
    }

public interface BillRepository extends JpaRepository<Bill, Long> {
}

数据库 database

在class MenuItem 中你应该添加注释@JsonIgnore 以防止返回的JSON 格式中的无限循环;一个账单有一个 BillDetails ,一个 BillDetails 有一个 MenuItem ,一个 MenuItem 有一个 BillDetails ,每个 BillDetail 都有一个 MenuItem 列表 ...

@Entity
@Table(name = "menuItem",
        uniqueConstraints = {
                @UniqueConstraint(name = "menu_item_name_unique", columnNames = "name")
        }
)
public class MenuItem {

    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @Column(name = "menu_item_id")
    private Long id;
    private ItemType type;
    private String name;
    private String description;
    private String imgUrl;
    private Double price;
    private MenuItemStatus status = MenuItemStatus.ENABLED;
    
    // ADD JSON IGNORE ANNOTATION HERE :
    @JsonIgnore
    @OneToMany(mappedBy = "menuItem", cascade = CascadeType.ALL)
    private List<BillDetail> billDetails = new ArrayList<>();