【问题标题】:How to use polymorphic associations with Spring Data REST如何使用 Spring Data REST 的多态关联
【发布时间】:2018-03-27 09:53:11
【问题描述】:

我在我的 Web 应用程序中使用 Spring Boot 1.5.7、Spring Data REST、Spring JPA、Hibernate、Spring HATEOAS、Spring Validation、Swage。 此应用程序提供 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 的超类。

@Entity
public class User extends AbstractEntity {

     private String name;

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

这样做,Hibernate 会创建一个带有两个附加列(id 和类型)的 Note 表来映射相关对象。

到目前为止,一切都像预期的那样。问题出在 REST 方面。 主要需要几个动作:

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

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

问题

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

好的,那我们来看看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 设置一个特定的控制器)。

【问题讨论】:

  • 我会为 /users 和 /notes 使用单独的端点。每个 Note 都将包含它所属的用户 ID。 Get on 用户应仅返回 Notes 的 ID。您可以使用 HATEOAS 之类的框架为用户导航/呈现注释。这是处理在 URL 中没有依赖关系的实体的非常基本和干净的方法。正如您提到的,您不希望每个 bean 有多个控制器(不知道为什么),您仍然可以拥有一个控制器并使用自己的逻辑在控制器方法中创建/操作 bean。
  • @ZakiAnwarHamdani 感谢您的回复。我一直在寻找 SDR 的特定解决方案,而不使用控制器,而只是使用存储库(稍后 SDR 在控制器/端点中转换)。从这个意义上说,我不想创建单独的控制器来处理这个问题。此外,问题是关于多态关联,因此注释可以同时引用客户或票证或我域的另一个实体。

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


【解决方案1】:

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

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

@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"),
})

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

【讨论】:

    猜你喜欢
    • 2019-12-25
    • 2018-10-08
    • 1970-01-01
    • 2019-08-14
    • 2017-04-22
    • 2019-07-23
    • 2015-07-06
    • 2014-04-23
    • 1970-01-01
    相关资源
    最近更新 更多