java - 如何使用 Spring Data REST 的多态关联

标签 java spring hibernate spring-mvc spring-data-rest

我在我的 Web 应用程序中使用 Spring Boot 1.5.7、Spring Data REST、Spring JPA、Hibernate、Spring HATEOAS、Spring Validation 和 Swagge。 此应用程序提供将由 Angular 客户端使用的 REST 端点。

简介

在我的模型中,很多实体都有一个列表 Note .用户、工单、退款等有一个 List<Note> . 根据一些documents我在网上发现,这似乎是一个使用@Any 的好例子。 这会很方便,所以我也可以避免连接表(User_note、Ticket_note、Refund_note 等)。

让我们看一个模型的例子:

@Entity
public class Note extends AbstractEntity {
    private static final long serialVersionUID = -5062313842902549565L;

    @Lob
    private String text;

     @RestResource(rel = "parent")
     @Any(fetch = FetchType.LAZY, optional = false, metaColumn = @Column(name ="item_type"))
     @AnyMetaDef(idType = "long", metaType = "string", metaValues = {
     @MetaValue(targetEntity = User.class, value = "User"),
     @MetaValue(targetEntity = Ticket.class, value = "Ticket"),
     @MetaValue(targetEntity = Refund.class, value = "Refund") })
     @JoinColumn(name = "item_id")
     private AbstractEntity parent;

你可以看到父级是AbstractEntity这是每个实体 bean 的父类(super class)。

@Entity
public class User extends AbstractEntity {

     private String name;

     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
     private List<Note> notes = new ArrayList<>();

为此,Hibernate 创建了一个 Note 表,其中包含两个附加列(id 和 type)以映射相关对象。

到目前为止,一切都像预期的那样。问题出在 REST 方面。 主要需要执行的操作很少:

  1. 为特定父实体(用户、票证等)插入注释
  2. 获取特定实体的笔记列表
  3. 从特定实体的列表中删除注释

Spring Data REST 根据您创建的存储库发布端点。我为每个实体创建了一个存储库。

问题

这时候问题就出现了。例如,如果你想给用户添加注释,你会希望调用 POST /api/v1/users/{id}/notes , 但不幸的是你不能根据 thisthis .从文档看来你可以只发布链接。并且仅仅因为没有他的 parent 就不存在笔记,我无法之前保存笔记然后使用链接将其加入到用户。无论如何,即使有可能我也不喜欢这个想法:我希望一切都在事务中。

好吧,那我们看看enpoint Note。你会看到一个 POST http://localhost:8080/api/v1/notes这似乎是保存笔记的完美选择。当您尝试保留这样的注释时,如果没有,就会出现此异常:

{
  "parent": 
    "http://localhost:8080/api/v1/users/1"
  ,
  "text": "string",
  "version": 0
}

和异常:

{
  "timestamp": "2017-10-15T22:37:06.668+0000",
  "status": 400,
  "error": "Bad Request",
  "exception": "org.springframework.http.converter.HttpMessageNotReadableException",
  "message": "Il valore del campo <null> deve essere di tipo <null>; è stato invece ricevuto il valore <null> di tipo <null>. Correggere il dato e riprovare.",
  "path": "/api/v1/notes",
  "cause": {
    "exception": "com.fasterxml.jackson.databind.JsonMappingException",
    "message": "Can not construct instance of it.rebus.server.model.AbstractEntity: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information\n at [Source: org.apache.catalina.connector.CoyoteInputStream@67a66b7d; line: 7, column: 5] (through reference chain: server.model.auditing.Note[\"parent\"])"
  }
}

这是可以理解的。 Spring 不了解创建 AbstractEntity 的具体类。我希望它可以从 URI 中发现这一点,但似乎没有。

然后让我们尝试获取用户的所有注释。在这种情况下,有端点 GET http://localhost:8080/api/v1/users/1/notes ,但我运气不好,因为端点返回 http 405 错误 ( I opened a related question )。

结论

我想知道如何使用多态关联解决我在使用 SDR 时遇到的这些问题。有没有一种方便的方法可以达到为模型的每个 bean 在 Notes 上提供 crud 操作的目标? (我想避免为每个 bean 设置一个特定的 Controller )。

最佳答案

我很确定你解决了你的问题,但我最近遇到了同样的问题。所以我会发布我是如何解决它的,希望能帮助其他人。

我必须在抽象类中指定反序列化策略。我用过:

@JsonTypeInfo(use = Id.NAME, property = "@entityType")
 @JsonSubTypes({
        @JsonSubTypes.Type(value = User.class, name = "User"),
        @JsonSubTypes.Type(value = Ticket.class, name = "Ticket"),
        @JsonSubTypes.Type(value = Refund.class, name = "Refund"),
})

因此,在 Controller 级别,当我收到 POST 请求时,我会根据您所说的“http”属性值稍微更改接收到的对象节点,将“@entityType”属性添加到父子节点。现在做那个小改动,Spring 应该能够知道应该创建哪个具体类的实例。

关于java - 如何使用 Spring Data REST 的多态关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46760781/

相关文章:

java - 如何将 Spring Boot 与 MySQL 数据库和 JPA 一起使用?

java - 当前时间/日期代码错误

java - 什么是 map[(int)x]++; 它有什么作用?

java - 在没有定界符的Java中拆分字符串,做数学运算,然后重新组合

java - spring工具套件创建可运行的jar错误查找配置文件

spring - 415 Spring 应用程序中的 POST 请求不支持 MediaType

mysql - 带有 hibernate 的 Spring 数据 : multiple row insert in one-to-many entity without cascade

java - 初始 SessionFactory 创建失败 : java. lang.NoClassDefFoundError: javax/persistence/EntityListeners

java - Walking Tree - 标签值的长度

java - 在Java中将数组的所有元素移回一个