如何使用Spring Data REST

时间:2017-10-15 22:50:20

标签: 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的超类。

@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方面。 几乎不需要采取任何行动:

  1. 为特定父实体(用户,故障单等)插入备注
  2. 获取特定实体的备注列表
  3. 从特定实体列表中删除备注
  4. Spring Data REST根据您创建的存储库发布端点。我为每个实体创建了一个存储库。

    问题

    此时出现问题。例如,如果您要向用户添加备注,则可能会拨打POST /api/v1/users/{id}/notes,但遗憾的是,您无法根据thisthis进行操作。从文档看来你可以发布链接。只是因为没有父母的情况下不存在音符,我之前无法保存音符,然后使用链接将其加入用户。无论如何,即使有可能我也不喜欢这个想法:我希望一切都在交易中。

    好的,那就让我们看看注意事项。你会看到一个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设置一个特定的控制器)。

1 个答案:

答案 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应该能够知道哪个具体类应该为其创建实例。