如何创建具有关联的新实体

时间:2018-05-18 10:19:15

标签: ajax spring spring-mvc spring-data-jpa spring-rest

假设我在前端有一个常规字段和下拉列表。 在这些下拉菜单中,用户可以选择选项,并且每个选项都链接到Spring数据JPA中的实体;

下拉列表包含一些标签以及指向相应实体的链接,作为。 然后,该值将在POST请求中传递给我们希望创建的实体的 PagingAndSorting存储库

假设这是一个拥有用户名的用户,并且必须与其中一个办事处(也是一个实体)相关联:

@Data
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name="users")
public class User{

@Id
@Coluemn(name="USER_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;

@Column(name="USER_NAME", nullable=false)
private String userName;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="OFFICE_ID", **nullable=false**)
private Office office;
}

我的第一个猜测是:     将 POST - 请求发送到http://localhost:8080/api/users/     的的contentType : '应用/ JSON'

{"userName":"Anton","office":"http://localhost:8080/api/offices/1"}

但它抛出异常

{
"cause": {
    "cause": null,
    "message": "Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/offices/1')\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 160] (through reference chain: test.domain.User[\"office\"])"
},
"message": "JSON parse error: Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/offices/1'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `test.domain.Office` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/office/1')\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 160] (through reference chain: test.domain.User[\"office\"])"
}

我做错了什么?

2 个答案:

答案 0 :(得分:0)

您正在发送一个URL资源作为字符串来代替JSON对象,并期望在Spring和jackson之间发生一些魔术以查找该值。当然,这不是正在发生的事情,杰克逊试图将URL的字符串值绑定到Office字段。这当然失败了,因为它不知道如何从字符串创建Office对象。

一种可能的解决方案是区分您的实体对象(代表您的数据库表的对象)和DTO(数据传输对象),在此原因中代表您与客户的合同。执行此操作时,您可以收到如下所示的用户对象:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User{

  private Long userId;

  private String userName;

  private Long officeId;

}

现在您可以简单地发送办公室ID而不是URL,并在您的代码中使用Spring数据存储库来查找office对象。之后,您可以构建您的实体用户对象,就像上面显示的对象一样,并保留它。

答案 1 :(得分:0)

原来是因为我使用了Lombok,它生成了自己的构造函数。 为了使它工作,我只需要像这样设置@AllArgsConstructor:

@AllArgsConstructor(suppressConstructorProperties = true)

现在它按预期工作:

Json发送给http://localhost:8080/api/users

{ "userName":"Anton", "office":"http://localhost:8080/api/offices/1" }

返回:

{ "userName":"Anton", "_links": { "self": { "href": "http://localhost:8080/api/users/28" }, "user": { "href": "http://localhost:8080/api/users/28" }, "office": { "href": "http://localhost:8080/api/users/28/office" } } }