在春季使用多对一映射时获得无限的Json响应[重复]

Posted

技术标签:

【中文标题】在春季使用多对一映射时获得无限的Json响应[重复]【英文标题】:Getting infinite Json response when using many to one mapping in spring [duplicate] 【发布时间】:2019-10-18 20:11:20 【问题描述】:

我正在尝试在春季创建两个实体之间的多对一映射。但是,当我尝试使用 restController 获取值时,我得到了

Java.lang.IllegalStateException:在 响应已提交

错误和无限的 JSON 响应。添加 JSON 忽略解决了这个问题,但我的回复中根本没有得到该列。我不知道如何解决这个问题。请帮忙。提前致谢。

这是我的实体:

@Entity
@Table(name="tbl1")
public class Data 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

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



    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="data_id", insertable = true, nullable = false, updatable = false)
    private DataList dataList1;



@Entity
@Table(name="tbl2")
public class DataList 

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="data_id")
    private Long dataId;



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



    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,mappedBy = "dataList1")
    private List<Data> data1;



存储库:

@Repository
@Transactional
public interface DataList extends JpaRepository<DataList,Long> 

@Repository
@Transactional
public interface Data extends JpaRepository<Data,Long> 

我的错误:Java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

【问题讨论】:

我没有使用任何html。我正在通过邮递员进行测试。 你是否实现了自己的 toString 方法或@JsonSerialize 方法?你在用lombok吗? 我正在使用龙目岛 【参考方案1】:

1) 一般而言,将fetch = FetchType.EAGER 放在@OneToMany 上并不是一个可取的做法。尝试将其设置为 LAZY。

2) 确保 Data 和 DataList 实体正确实现 equals()hashCode() 方法。

【讨论】:

如何检查它们是否正确实现了 equals() 和 hashCode()。 我的意思是你要确保它们得到实施。它们是否有效由您检查 是的,它们已实现。 RestController 方法上是否有@Transactional? 我正在使用 CRUD 存储库提供的默认 findAll() 方法。我已将 @Transactional 添加到我的存储库中。我已将存储库添加到我的问题中。【参考方案2】:

当 JSON 序列化程序试图一次又一次地递归地序列化这两个实体时,就会发生这种情况。

因此,在序列化Data 时,其成员dataList1 的类型为DataList,其中还包含List&lt;Data&gt;,此循环将是无限的。

理想情况下,在这种情况下,实体应映射到其他用于序列化和响应的模型,或者其中一个模型需要为 @JsonIgnore 以避免这种递归循环。

【讨论】:

添加@Json Ignore 会完全隐藏响应。我不希望这样。 所以,数据包含数据列表,数据列表进一步包含数据。你也想要这个内部数据变量吗? 我希望当我得到数据列表时,我也应该得到内部数据,当我得到数据时,我也应该得到那个数据列表。 当你谈到从数据列表中获取数据和从数据中获取数据列表时。你说的是java代码还是json响应? 在 json 响应中,因为我需要在前端应用程序中使用此响应。【参考方案3】:
    EAGER 是一种不好的做法。使用LAZY,当需要相关实体时,使用fetch join查询。 很可能是双向关系中的问题。您使用Data 列表获取DataList。并且列表ListData 中的每个Data 再次引用。 序列化 json 时更可能是堆栈溢出。所以请记住一条规则:永远不要让控制器休眠实体。编写一个映射器,将这些实体映射到Dto 对象。

您可能认为将某些模型映射到另一个模型非常无聊。但在这里以另一种方式。不应将休眠实体传递到前端。我的应用程序使用了几种类型的对象:Entities(从 DB 获取时)、DTO(将实体映射到 DTO 并提供它们的服务组件时)、Shared(将 DTO 映射到 Shared 并共享作为对我的微服务之间的控制器)和Model(从响应映射到模型并提供给模板引擎,例如freemarker)。您可能不需要这种模型层次结构。

创建 DTO:

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class DataListDto 

    private Long dataId;
    private String userName;

    private List<DataDto> data1;




@AllArgsConstructor
@NoArgsConstructor
@Getter
public class DataDto 

    private long id;
    private String customer;


编写你的映射器:

 public class DataListMapper 

    public static DataListDto mapToDto(DataList dataList) 
        return new DataListDto(dataList.getDataId(), dataList.getUserName(), dataList.getData1().stream().map(x -> DataListMapper.mapToDto(x).collect(Collectors.toList)))
    

    public static DataDto mapToDto(Data data) 
        return new DataDto(data.getId(), data.getCustomer());
    

您的服务:

public class DataListService 
            @Autowired
            private DataListRepository dataListRepository;


            public List<DataListDto> getAllData() 
                List<DataList> dataLists = this.dataListRepository.findAll();
                return dataLists.stream().map(x->DataListMapper.mapToDto(x)).collect(Collectors.toList());
            
        

【讨论】:

你能举个例子说明如何做到这一点。 @rock11 我编辑答案。

以上是关于在春季使用多对一映射时获得无限的Json响应[重复]的主要内容,如果未能解决你的问题,请参考以下文章

JPA Spring Boot 微服务 - 使用两个多对一映射持久化实体时的无限循环

多对一映射不允许属性

Nhibernate 多对一映射返回重复值

Mybatis 高级映射,一对一,一对多,多对多映射

hibernate 多对一 一对多 出现死循环

hibernate 一对多 多对一映射关系