使用 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 添加到 PointRequest,将 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 的运作方式有根本性的误解吗?我什至应该使用 DBRefs 吗?或者这根本不可能用 MongoDB?

提前致谢,抱歉问题太长了!

编辑

Points 实际上被添加为 DBRefs (通过手动查看数据库验证),但看起来 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),这好像是你在做的。