如何解决使用@OneToMany 关系与@RestController 没有无限recution 的最佳实践是什么
我有以下几点:
@Data
@Entity
@Table(name = "floor")
public class Floor {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "floor_id")
private Long id;
@JsonIgnoreProperties(value= {"floor","registrations"})
@OneToMany (mappedBy = "floor",cascade = CascadeType.ALL)
private Set<Slot> slots;
}
@Entity
@Table(name = "slot")
public class Slot {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "slot_id")
private Long id;
@ManyToOne
@JoinColumn(name = "floor_id")
private Floor floor;
}
@RestController
public class Controller {
@Autowired
FloorService floorService;
@GetMapping("/api/floors")
public List<Floor> getAllFloors() {
// calls repository.findAll()
return floorService.getAllFloors();
}
}
访问 API 端点时,我得到:
2021-03-06 06:52:30.038 WARN 699889 --- [tp1028811481-19] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.veebzone.parking.model.Floor["slots"])]
通过使用 /api/floors 端点获取每个楼层的列表,我的目标是在其 JSON 元素中获取与每个楼层关联的插槽列表。
实现这一目标的最佳做法是什么:
- 我的方法是正确的,只是一些配置问题?
- 我应该改用服务返回的一些 DTO(将插槽列表作为子元素)并使用 JSONIgnore 作为插槽字段。
- 别的东西
解决方法
最好使用 DTO,这样您就可以将数据库类与 REST API 分离。
如果您想要快速解决方案,您可以使用 Jackson 的 @JsonManagedReference
和 @JsonBackReference
。这将告诉 Jackson 存在递归/双向引用,以及如何序列化它:
class Floor {
@JsonManagedReference
Set<Slot> slots;
}
class Slot {
@JsonBackReference
Floor floor;
}
,
我假设您在调用端点时想要这样的东西(一个楼层数组,每个楼层都有一个插槽数组):
[
{ "id": 1,"slots": [
{ "id": 1 },{ "id": 2 }
]
},{ "id": 2,"slots": [
{ "id": 3 }
]
}
]
您有一个无限递归,因为在 Spring Boot 中用于写入/读取 Json 的默认库 Jackson(就像在您的 enpoint 中一样)尝试使用您类中的每个字段来构建 Json。
所以发生的事情是,Jackson 试图在输出 Json 中写入第一层,但是这个层与第一槽相关,而第一槽与第一层相关,依此类推。这是你的循环。
如果你想打破循环,你有两个选择:
- 删除 Floor 类中的 @JsonIgnoreProperties(value= {"floor","registrations"}),然后添加 @JsonIgnore Slot 类中的 floor 字段。这样,Jackson 就不会序列化该字段。
- 使用 @JsonSerialize 为 Floor 类构建您自己的序列化程序(请参阅 this)。
现在,哪个选项更好取决于您的实体有多大以及实体之间的关系有多复杂。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。