我正在制作一个简单的社交媒体平台,并使用 MongoDB 与 Morphia 和 Spring boot。 在我的数据库中,用户有一个他们关注的用户列表,但是如果该列表包含也关注他们的用户,则会创建无限的来回加载每个用户的数据。我怎样才能防止这样的问题?我尝试使用 @Reference(lazy=true) 启用延迟加载,但这没有帮助。
对于任何在使用 MongoDB 和 Spring-Boot 时偶然发现这个问题或递归问题的人,解决方案可能是使用 Jackson JSON Views,特别是如果您使用 SpringMVC 的 RestControllers。
按如下方式添加 JsonViews 类应该可以工作:
public class JsonViews {
public interface Public {}
}
然后,您可以将以下注释添加到您想要包含在任何给定控制器 GET 请求的响应中的字段。
public class Foo {
@Id @JsonView(JsonViews.Public.class) String id;
@DocumentReference(lazy = true) @JsonView(JsonViews.Public.class) Bar someField;
}
public class Bar {
@Id @JsonView(JsonViews.Public.class) String id;
@ReadOnlyProperty @DocumentReference(lookup="{ 'bar':?#{#self._id} }") List<Foo> foos;
}
public class FooController {
@GetMapping @JsonView(JsonViews.Public.class)
public List<Foo> getAll() { return fooList; }
}
这应该创建以下响应
[
{
id: "abc",
bar: {
id: "bcd",
}
},
{
id: "def",
bar: {
id: "ghi",
}
},
]
要修复在这种情况下返回 Bar 的控制器,您可以创建另一个 JsonViews 样式类 + 接口,但我会将其放置在 Bar 类本身中,作为封装/隔离 Bar 的特定 JsonView 逻辑的一种方式。这会将类更改为以下内容:
public class Foo {
@Id @JsonView({ JsonViews.Public.class, Bar.PublicView.class }) String id;
@DocumentReference(lazy = true) @JsonView(JsonViews.Public.class) Bar someField;
}
public class Bar {
@Id @JsonView({ JsonViews.Public.class, PublicView.class }) String id;
@ReadOnlyProperty @DocumentReference(lookup="{ 'bar':?#{#self._id} }")
@JsonView(PublicView.class) List<Foo> foos;
public interface PublicView {}
}
然后在你的控制器中你可以这样做:
public class BarController {
@GetMapping @JsonView(Bar.PublicView.class)
public List<Bar> getAll() { return barList; }
}
这应该创建以下响应
[
{
id: "cba",
foos: [
{
id: "fed"
},
{
id: "ihg"
}
]
},
{
id: "edc",
foos: [
{
id: "xyz"
},
{
id: "zyx"
}
]
}
]
由于 SpringMVC 的 RestController 需要将数据解析为响应正文的 JSON 字符串,因此 Spring 使用的 Jackson JSON Serializer 默认情况下将解析 Lazy DocumentReference。当然,如果您有循环引用,这将导致无限递归(如果您有一个属性指向每个类中的另一个模型,则可能是这种情况)
您可以查看 Spring-Boot 的 Jackson JSONViews 页面以获取更多信息。