在Spring Data REST中发布@OneToMany子资源关联


103

目前,我有一个使用Spring Data REST的Spring Boot应用程序。我有一个域实体Post,它@OneToMany与另一个域实体有关系Comment。这些类的结构如下:

Post.java:

@Entity
public class Post {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;
    private String title;

    @OneToMany
    private List<Comment> comments;

    // Standard getters and setters...
}

Comment.java:

@Entity
public class Comment {

    @Id
    @GeneratedValue
    private long id;
    private String author;
    private String content;

    @ManyToOne
    private Post post;

    // Standard getters and setters...
}

他们的Spring Data REST JPA存储库是以下各项的基本实现CrudRepository

PostRepository.java:

public interface PostRepository extends CrudRepository<Post, Long> { }

CommentRepository.java:

public interface CommentRepository extends CrudRepository<Comment, Long> { }

应用程序入口点是一个标准的,简单的Spring Boot应用程序。一切都已配置库存。

应用程序

@Configuration
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableAutoConfiguration
public class Application {

    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

一切似乎正常工作。当我运行该应用程序时,一切似乎都能正常工作。我可以发布一个新的Post对象,http://localhost:8080/posts就像这样:

身体: {"author":"testAuthor", "title":"test", "content":"hello world"}

结果http://localhost:8080/posts/1

{
    "author": "testAuthor",
    "content": "hello world",
    "title": "test",
    "_links": {
        "self": {
            "href": "http://localhost:8080/posts/1"
        },
        "comments": {
            "href": "http://localhost:8080/posts/1/comments"
        }
    }
}

但是,当我在GET处执行操作时,http://localhost:8080/posts/1/comments{}返回一个空对象,并且如果我尝试对同一URI发表评论,则会收到HTTP 405方法不允许。

创建Comment资源并将其与此关联的正确方法是什么Posthttp://localhost:8080/comments如果可能的话,我想避免直接发布。


9
7天后,仍然没有运气。如果有人知道如何使这种行为起作用,请告诉我。谢谢!
ccampo 2014年

您在使用@RepositoryRestResource还是控制器?看到该代码也将很有帮助。
Magnus Lassi 2014年

我正在使用Spring Boot数据休息,它对我
有用

Answers:


47

您必须先发布评论,而在发布评论时,您可以创建关联发布实体。

它看起来应该像下面这样:

http://{server:port}/comment METHOD:POST

{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}

它会很好地工作。


2
这对我有用。只需确保其author.post可写(例如,使用二传手或@JsonValue注解)即可
scheffield 2015年

1
将评论从一个帖子移到另一个帖子时,这是否也应适用于补丁请求?
aycanadal

2
这将是我(非常)首选的方法,但是它似乎不适用于我。:(它会创建注释,但不会在解析表(POST_COMMENTS)中创建行。关于如何解决的任何建议?
banncee 2015年

3
对于场景(例如,场所和地址实体),场所必须具有地址且地址必须与场所相关联的情形,该方法将是什么?我的意思是...为了避免创建一个可能永远不会分配给任何东西的孤立地址?也许我说错了,但是客户端应用程序绝不应该负责维护数据库内的一致性。我不能依靠客户端应用程序创建地址,然后确定分配给场地。有没有一种方法可以通过创建实际资源来发布子资源(在这种情况下为Address实体),以便避免不一致?
–'apostrophedottilde

2
我尝试执行此操作(请参阅此处),但是由于某种原因,仅创建了资源,而不创建了关联。
显示名称

55

假设您已经发现了发布URI,因此也发现了关联资源的URI($association_uri在下面考虑),通常会执行以下步骤:

  1. 发现集合资源管理注释:

    curl -X GET http://localhost:8080
    
    200 OK
    { _links : {
        comments : { href : "…" },
        posts :  { href : "…" }
      }
    }
    
  2. 按照comments链接和POST您的数据到资源:

    curl -X POST -H "Content-Type: application/json" $url 
    {  // your payload // … }
    
    201 Created
    Location: $comment_url
    
  3. 通过向PUT关联URI 发出a ,将评论分配给帖子。

    curl -X PUT -H "Content-Type: text/uri-list" $association_url
    $comment_url
    
    204 No Content
    

请注意,在最后一步中,根据的规范text/uri-list,您可以提交多个URI,这些注释标识用换行符分隔的注释,以一次分配多个注释。

关于一般设计决策的更多说明。帖子/评论示例通常是汇总的一个很好的示例,这意味着我要避免从Comment到的反向引用Post,也要避免CommentRepository完全引用。如果注释本身没有生命周期(它们通常没有组合样式的关系),则宁愿直接以内联方式呈现注释,也可以使用来处理添加和删除注释的整个过程。JSON补丁。Spring Data REST 在即将发布的2.2版本的最新候选版本中增加了对此的支持


4
下来的选民对这里感兴趣的是,投票的理由是;)。
奥利弗·德罗博姆

3
我不确定选民是否失望...我什至没有做到这一点的声誉!我不一定喜欢在帖子中插入评论的原因是,考虑当我对一个帖子有成千上万条评论时(不太可能)的情况。我希望能够对评论集进行分页,而不是每次我要访问帖子内容时都获得全部评论。
ccampo 2014年

25
我发表评论的最直观的方法是对localhost:8080 / posts / 1 / comments进行POST 。这不是最简单,最有意义的方法吗?同时,您仍然应该能够拥有一个专用的注释存储库。是春季还是HAL标准不允许这样做?
艾阿卡纳达尔(Aycanadal)

4
@OliverGierke这仍然是推荐/唯一的方法吗?如果孩子不可为空(@JoinColumn(nullable=false))怎么办?首先将无法发布子项,然后再进行PUT / PATCH父项关联。
JW Lim

2
是否有使用Spring Data Rest创建的api的指南?我已经用Google搜索了2个小时,却一无所获。谢谢!
Skeeve '16

2

映射关联和组成有2种类型。在关联的情况下,我们使用了联接表的概念,例如

员工-1至n->部门

因此,在关联员工,部门,员工部门的情况下将创建3个表

您只需要在代码中创建EmployeeRepository。除了那个映射应该是这样的:

class EmployeeEntity{

@OnetoMany(CascadeType.ALL)
   private List<Department> depts {

   }

}

部门实体将不包含任何用于外键的映射...因此,当您尝试在单个json请求中尝试添加带有Department的Employee的POST请求时,它将被添加...。


1

我遇到了同样的情况,我不得不删除子实体的存储库类,因为我已经使用了一对多映射,并通过主实体本身提取数据。现在,我得到了整个数据响应。


1
您谈论的事情很容易通过投影完成
kboom

0

对于oneToMany映射,只需为要映射的类创建一个POJO,并为其添加@OneToMany批注,并且它将在内部将其映射到该Table id。

另外,您需要为要检索数据的类实现Serializable接口。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.