在春季使用多对一映射时获得无限的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<Data>
,此循环将是无限的。
理想情况下,在这种情况下,实体应映射到其他用于序列化和响应的模型,或者其中一个模型需要为 @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响应[重复]的主要内容,如果未能解决你的问题,请参考以下文章