使用 Spring Data REST 和 MongoDB 访问和更新关联资源
Accessing and updating association resources with Spring Data REST and MongoDB
我不完全理解如何使用 Spring Data REST 和 MongoDB 创建和访问关联资源。我注意到一些奇怪的行为,希望能在这里得到一些澄清。
我有一个简单的对象模型,其中一种资源类型 (Request
) 包含另一种资源类型 (Point
) 的对象列表。两种资源都是顶级资源,即有自己的 Repository
接口。
我希望能够通过 POST 将 /requests/{id}/points
添加到 Point
到 Request
,将 link 添加到现有的点(正如我从 this question 知道的,我不能只 POST 一个点作为 JSON 有效载荷)。
此外,我希望能够 GET /requests/{id}/points
来检索与请求关联的所有点。
这是我的对象模型(getters/setters省略):
Request.java
public class Request {
@Id
private String id;
private String name;
@DBRef
private List<Point> points = new ArrayList<>();
}
RequestRepository.java
public interface RequestRepository extends MongoRepository<Request, String> {
}
Point.java
@Data
public class Point {
@Id
private String id;
private String name;
}
PointRepository.java
public interface PointRepository extends MongoRepository<Point, String> {
}
假设我 POST 一个新的 Request
。然后在 /requests 上执行 GET 给我这个:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests",
"templated" : false
}
},
"_embedded" : {
"requests" : [ {
"name" : "request 1",
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"request" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"points" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points",
"templated" : false
}
}
} ]
}
}
所以我有一个 points
link 在那里。好的。现在,如果我在 /requests/55e5dc47b7605d55c7c361ba
上执行 GET,我会注意到 奇怪的事情 #1。没有了 points
link:
{
"name" : "request 1",
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"request" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
}
}
}
但不管怎样,现在暂时忘掉它,让我们 POST 一个点(获得 ID 55e5e225b76012c2e08f1e3e
)并 link 它到请求:
curl -X PUT -H "ContentType: text/uri-list" http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points
-d "http://localhost:8080/points/55e5e225b76012c2e08f1e3e"
204 No Content
这似乎奏效了。好的,现在如果我在 http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points
上执行 GET,我希望看到我刚刚添加的点,对吧?输入 strange thing #2,我得到以下响应:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points",
"templated" : false
}
}
}
所以在这一点上我意识到我做错了什么。有人可以向我解释这里发生了什么吗?我对 SDR 的运作方式有根本性的误解吗?我什至应该使用 DBRef
s 吗?或者这根本不可能用 MongoDB?
提前致谢,抱歉问题太长了!
编辑
Point
s 是 实际上被添加为 DBRef
s (通过手动查看数据库验证),但看起来 SDR 是不还给他们。如果我明确要求 http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points/55e5e225b76012c2e08f1e3e
,那么我会得到以下响应:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/points/55e5e225b76012c2e08f1e3e",
"templated" : false
},
"point" : {
"href" : "http://localhost:8080/points/55e5e225b76012c2e08f1e3e",
"templated" : false
}
}
}
这也很奇怪...我的Point.name
在哪里?
这两个方面都是由 glitch in Spring Framework 4.2.0 引起的,Spring Boot 1.3 M4 已升级到导致 Spring Data RESTs 自定义序列化程序在某些情况下未应用。这已在 Spring 4.1.2 中修复。要将您的 Gradle 项目升级到该版本,请将 Boot 插件升级到 1.3,然后使用以下声明将 Spring 版本修复到 4.2.1:
ext['spring.version'] = '4.2.1.RELEASE'
确保用空值正确初始化 collection,因为 null
值将导致返回 404 Not Found
。空列表将产生正确的 HAL 输出。
一般来说,关联资源应该与已经存在的资源一起使用,尤其是。使用 Spring Data MongoDB 没有其他选择,因为它没有可达性持久性。 IE。您需要首先保留相关实例(又名 POST
到它的 collection 资源并获得 Location
header 返回)并分配刚刚创建的资源(又名. PUT
or POST
刚刚获取到的Location to the association resource),这好像是你在做的。
我不完全理解如何使用 Spring Data REST 和 MongoDB 创建和访问关联资源。我注意到一些奇怪的行为,希望能在这里得到一些澄清。
我有一个简单的对象模型,其中一种资源类型 (Request
) 包含另一种资源类型 (Point
) 的对象列表。两种资源都是顶级资源,即有自己的 Repository
接口。
我希望能够通过 POST 将 /requests/{id}/points
添加到 Point
到 Request
,将 link 添加到现有的点(正如我从 this question 知道的,我不能只 POST 一个点作为 JSON 有效载荷)。
此外,我希望能够 GET /requests/{id}/points
来检索与请求关联的所有点。
这是我的对象模型(getters/setters省略):
Request.java
public class Request {
@Id
private String id;
private String name;
@DBRef
private List<Point> points = new ArrayList<>();
}
RequestRepository.java
public interface RequestRepository extends MongoRepository<Request, String> {
}
Point.java
@Data
public class Point {
@Id
private String id;
private String name;
}
PointRepository.java
public interface PointRepository extends MongoRepository<Point, String> {
}
假设我 POST 一个新的 Request
。然后在 /requests 上执行 GET 给我这个:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests",
"templated" : false
}
},
"_embedded" : {
"requests" : [ {
"name" : "request 1",
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"request" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"points" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points",
"templated" : false
}
}
} ]
}
}
所以我有一个 points
link 在那里。好的。现在,如果我在 /requests/55e5dc47b7605d55c7c361ba
上执行 GET,我会注意到 奇怪的事情 #1。没有了 points
link:
{
"name" : "request 1",
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
},
"request" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba",
"templated" : false
}
}
}
但不管怎样,现在暂时忘掉它,让我们 POST 一个点(获得 ID 55e5e225b76012c2e08f1e3e
)并 link 它到请求:
curl -X PUT -H "ContentType: text/uri-list" http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points
-d "http://localhost:8080/points/55e5e225b76012c2e08f1e3e"
204 No Content
这似乎奏效了。好的,现在如果我在 http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points
上执行 GET,我希望看到我刚刚添加的点,对吧?输入 strange thing #2,我得到以下响应:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points",
"templated" : false
}
}
}
所以在这一点上我意识到我做错了什么。有人可以向我解释这里发生了什么吗?我对 SDR 的运作方式有根本性的误解吗?我什至应该使用 DBRef
s 吗?或者这根本不可能用 MongoDB?
提前致谢,抱歉问题太长了!
编辑
Point
s 是 实际上被添加为 DBRef
s (通过手动查看数据库验证),但看起来 SDR 是不还给他们。如果我明确要求 http://localhost:8080/requests/55e5dc47b7605d55c7c361ba/points/55e5e225b76012c2e08f1e3e
,那么我会得到以下响应:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/points/55e5e225b76012c2e08f1e3e",
"templated" : false
},
"point" : {
"href" : "http://localhost:8080/points/55e5e225b76012c2e08f1e3e",
"templated" : false
}
}
}
这也很奇怪...我的Point.name
在哪里?
这两个方面都是由 glitch in Spring Framework 4.2.0 引起的,Spring Boot 1.3 M4 已升级到导致 Spring Data RESTs 自定义序列化程序在某些情况下未应用。这已在 Spring 4.1.2 中修复。要将您的 Gradle 项目升级到该版本,请将 Boot 插件升级到 1.3,然后使用以下声明将 Spring 版本修复到 4.2.1:
ext['spring.version'] = '4.2.1.RELEASE'
确保用空值正确初始化 collection,因为 null
值将导致返回 404 Not Found
。空列表将产生正确的 HAL 输出。
一般来说,关联资源应该与已经存在的资源一起使用,尤其是。使用 Spring Data MongoDB 没有其他选择,因为它没有可达性持久性。 IE。您需要首先保留相关实例(又名 POST
到它的 collection 资源并获得 Location
header 返回)并分配刚刚创建的资源(又名. PUT
or POST
刚刚获取到的Location to the association resource),这好像是你在做的。