当前位置: 首页 > 知识库问答 >
问题:

Spring Boot REST Api-使用实体类之间的1: M关系,响应数据没有显示预期的结果

刘升
2023-03-14

所以我试图建立一个网站使用Spring Boot和React。

到目前为止,我有一个注册表单连接到我的spring后端localhost:8080/api/test/customers(这里有CRUD操作的endpoint)

这很好,我可以从我的React表单将表单数据发布到它,并且我可以在postman中查看它,以从API获得预期的响应。

但现在我在网站上有了另一个表单(一个用户输入姓名、电子邮件和消息的联系表单)。

我在localhost上有这个API:8080/API/form/contact,用于GET和POST请求。

我已经使用1: M关系映射了实体“客户”和“联系表单”,该关系在联系表单表中包含作为FK的客户标识。

问题是,自从我添加了这个,API的响应就不是我所期望的。

邮递员的回复持续了200行,只是嵌套了同样的东西

对客户API的GET请求(注册)

对联系人表单API的GET请求

我的实体类

顾客java-删除了验证注释,使其更易于阅读

@Entity
@Table(name="customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="customer_id")
    private int customerId;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(name="email_address")
    private String emailAddress;

    @Column(name="date_of_birth")
    private Date dateOfBirth;

    @Column(name="mobile_number")
    private String mobileNumber;

    @Column(name="password")
    private String password;

    @OneToMany(mappedBy = "customer")
    private Set<ContactForm> contactForm;

    // default & arg constructor
    // getters and setters

}


联系方式。java-删除了验证注释,使其更易于阅读

@Entity
@Table(name="contact_form")
public class ContactForm {

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

    @Column(name="name")
    private String name;

    @Column(name="email_address")
    private String emailAddress;

    @Column(name="message")
    private String message;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;

    // default and arg constructor
    // getters & setters

}

这两个表的MySQL DDL

顾客


CREATE TABLE `customer` (
  `customer_id` int NOT NULL AUTO_INCREMENT,
  `mobile_number` varchar(12) DEFAULT NULL,
  `date_of_birth` date DEFAULT NULL,
  `email_address` varchar(255) DEFAULT NULL,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`customer_id`)
)

contact_form


CREATE TABLE `contact_form` (
  `contact_form_id` int NOT NULL AUTO_INCREMENT,
  `email_address` varchar(255) NOT NULL,
  `message` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `customer_id` int DEFAULT NULL,
  PRIMARY KEY (`contact_form_id`),
  FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`)
) 

客户控制器类

具有标准endpoint的控制器类,与ContactForm控制器相同

我不能再向任何一个endpoint发布数据了,请有人告诉我为什么会发生这种情况,我想记录下用户和他们以前的所有消息。

共有2个答案

淳于健
2023-03-14

无论是否使用DTO,您引用了Customer,它再次引用了ContactForm它引用了Customer,从而导致对对象的递归引用。

避免这种情况的一种简单方法是使用@JsonManagedReference@JsonBackReference,这里介绍了这两种方法。

另一种方法是在子对象上使用@JsonIgnore,这取决于API的交互方式。

这两者都会告诉Jackson忽略序列化上的子对象

宗政松
2023-03-14

我强烈建议查看DTO模式,通过REST公开您的域对象,只包含必要的信息。

直接公开ORM实体容易出错,不会抽象API内部,甚至会造成重大安全风险。

例如,创建UserDtoMessageDto类:

public class UserDto {
    private int customerId;
    private List<MessageDto> messages;
}

public class MessageDto {
    private String content;
    private String recipient;
    // other relevant fields
}

并从rest控制器方法返回UserDto(或其列表)。

您正在描述的实际问题是,您的ORM映射在顾客接触表之间构建了一个循环图。@ManyToOne/@code>@ManyToOne关系似乎无法正常工作。

一般来说,我建议不要以这种循环方式映射实体,而是使它们只能在一个方向上导航(例如,Customer-

  • 它可能会导致自动、意外地将数据库的很大一部分加载到内存中,以进行看似很小的查询
  • 它可以导致非结构化领域模型设计

后一个问题是在应用程序增长时出现的,以后可能更难解决:
假设您的应用程序和团队增长,并且多人应该主要独立地处理不同的部分。因此,您需要重构现有的代码库,并创建两个模块:customercontact
客户保存客户的基本数据(姓名、地址、电子邮件等)。它的唯一目的是管理客户的生命周期(创建客户、更改地址或名称、搜索特定客户等)
联系人实现与公司互动的方式:客户的联系人表单、尚未成为您客户的人的联系人表单以及员工回复这些消息的方式。

现在这两个模块应该解耦,因此一个模块中的更改对另一个模块的影响尽可能小
要实现这一点,您应该在两个模块之间只有html" target="_blank">定义良好的依赖关系,而通常模块之间没有循环依赖关系。

如果在此之前构建的代码通过ORM图(或其他方法)在不同“域”的实体之间来回导航,您将很难将这些东西分开。

现在,所有这些都有点遥不可及,仍然无法解决您手头的问题(与@flagalacy answer相反)
如果类之间引入的依赖关系是必要的和有用的,那么我建议只考虑一般的可导航映射,以及进一步的含义。

编辑:详细说明循环映射和更深层映射的问题。

 类似资料:
  • 我在显示实体产品和订单项的记录时遇到了大问题。这是一对多关系。 我向产品实体添加了记录,没有任何问题,我在以下函数中执行OrderItem输入: 这似乎没问题,我最大的问题是显示每个产品的所有订单项。关系产品==== 我尝试显示fetchedResult 我知道product中product中的relationship对象是NSSet,如下所示: 我在不同的项目中也用同样的方法,但我真的不知道为什

  • 问题内容: 我正在生成要显示在折线图中的数据。不幸的是,我无法弄清楚如何使上面的查询显示0来表示没有用户注册的日期。所以目前我的输出可能是这样的: 但是我想要的是 我目前确实有一个工作版本,该版本将MySQL结果存储到数组中,然后PHP循环遍历并填补空白。这似乎很混乱,我希望可以通过MySQL解决方案。我已经对该站点进行了很好的搜索,但是努力了解一些实现。有什么建议么? 问题答案: 您可以使用My

  • 我正在为我的项目使用Spring Data JPA(以hibernate作为提供程序),并想知道何时需要实体之间的双向映射? 在我的用例中,我有一个实体,与实体具有关系。目前,我在实体中没有相应的关系。从我所能理解的查看其他帖子,除非我需要通过我的实体/Hibernate删除,否则我可能不需要这样做。我想知道通过双向关系我还能得到什么? 这是我的,不包括访问者: 这是,不包括访问器: 如果我一直在

  • 我们在OpenAM配置中标记了“断言已签名”, 而如果来自IDP的SAML响应经过签名,而SAML断言没有经过签名,OpenAM会把这个SAML响应视为有效的SAML响应吗? 注:openam 版本 13.0.0

  • 问题内容: 我们目前正在为一家专业公司内部实施类似于CRM的解决方案。由于所存储信息的性质以及信息的不同值和键,我们决定使用文档存储数据库,因为它非常适合此用途(在这种情况下,我们选择MongoDB)。 作为此CRM解决方案的一部分,我们希望存储实体之间的关系和关联,例如包括存储利益冲突,股东,受托人等的冲突。以最有效的方式将所有这些实体链接在一起,我们确定了“关系”的中心模型是必要的。所有关系都

  • 我正在学习DDD和六角结构,我想我已经掌握了基本知识。然而,有一件事我不确定如何解决:我如何向用户显示数据? 例如,我得到了一个简单的域,其中包含一个带有某些功能的Worker实体(某些方法会导致实体更改)和一个WorkerRepository,这样我就可以持久化Worker了。我得到了一个应用程序层,其中包含一些命令和命令总线来操作域(比如创建员工和更新他们的工作时间,持久化更改),以及一个基础