我在我的 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 方面。 主要需要执行的操作很少:
- 为特定父实体(用户、票证等)插入注释
- 获取特定实体的笔记列表
- 从特定实体的列表中删除注释
Spring Data REST 根据您创建的存储库发布端点。我为每个实体创建了一个存储库。
问题
这时候问题就出现了。例如,如果你想给用户添加注释,你会希望调用 POST /api/v1/users/{id}/notes
, 但不幸的是你不能根据 this和 this .从文档看来你可以只发布链接。并且仅仅因为没有他的 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/