【发布时间】: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 方面。 主要需要几个动作:
- 为特定父实体(用户、票证等)插入注释
- 获取特定实体的笔记列表
- 从特定实体列表中删除注释
Spring Data REST 根据您创建的存储库发布端点。我为每个实体创建了一个存储库。
问题
此时出现问题。例如,如果您想为用户添加注释,您希望调用POST /api/v1/users/{id}/notes,但不幸的是您不能根据this 和this。从文档看来,您可以只发布链接。仅仅因为没有他的父母就没有笔记,我无法保存笔记,然后使用链接将其加入用户。无论如何,即使有可能,我也不喜欢这个想法:我希望一切都在交易中。
好的,那我们来看看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