我在我的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的超类。
@Entity
public class User extends AbstractEntity {
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Note> notes = new ArrayList<>();
这样做,Hibernate创建一个带有两个附加列(id和type)的Note表来映射相关对象。
到目前为止,一切都像预期的那样。问题出在REST方面。 几乎不需要采取任何行动:
Spring Data REST根据您创建的存储库发布端点。我为每个实体创建了一个存储库。
问题
此时出现问题。例如,如果您要向用户添加备注,则可能会拨打POST /api/v1/users/{id}/notes
,但遗憾的是,您无法根据this和this进行操作。从文档看来你可以发布链接。只是因为没有父母的情况下不存在音符,我之前无法保存音符,然后使用链接将其加入用户。无论如何,即使有可能我也不喜欢这个想法:我希望一切都在交易中。
好的,那就让我们看看注意事项。你会看到一个POST http://localhost:8080/api/v1/notes
似乎完美地保存了Note。如果不是这样,当你试图坚持这样的注释时,你就会有这个例外:
{
"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设置一个特定的控制器)。
答案 0 :(得分: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应该能够知道哪个具体类应该为其创建实例。