Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate Spring@RequestBody不查找对象_Hibernate_Spring Mvc - Fatal编程技术网

Hibernate Spring@RequestBody不查找对象

Hibernate Spring@RequestBody不查找对象,hibernate,spring-mvc,Hibernate,Spring Mvc,我正在使用SpringMVC/Hibernate编写一个REST服务,似乎@RequestBody是接受一组参数并将其映射到POJO的推荐方法。但是,通过POST发送的ID似乎被转换为null,而不是实际的对象。一些示例代码可以更好地解释 服务很简单: @ResponseBody @RequestMapping(value="add", method = RequestMethod.POST) public ServiceResponse addTx(@RequestBody Transacti

我正在使用SpringMVC/Hibernate编写一个REST服务,似乎@RequestBody是接受一组参数并将其映射到POJO的推荐方法。但是,通过POST发送的ID似乎被转换为null,而不是实际的对象。一些示例代码可以更好地解释

服务很简单:

@ResponseBody
@RequestMapping(value="add", method = RequestMethod.POST)
public ServiceResponse addTx(@RequestBody Transaction tx) {
    ...
    return ServiceResponse;
}
交易实体有一个账户实体:

@Entity
@Table(name="Transaction")
public class Transaction {
    @Column(name="code")
    private String code;
    @OneToOne
    @JoinColumn(name="accountId")
    private Account account;
    @Column(name="amount")
    private int amount;
    ...
}
来自我的浏览器的POST请求有效负载显示:

{code: "ascasc", amount: 23, accountId: 1, ... }

但在服务器端,构造的事务对象的帐户值为null。i、 e.1的accountId未转换为Account对象。我遗漏了什么吗?

你描述的行为是正确的。当您使用
@RequestBody
时,它对持久层一无所知,只是将请求的主体映射到目标对象

因此,当您发布包含
accountId
的JSON时,Spring将尝试查找目标对象的
accountId
属性,但它不存在(目标对象只有
account
属性),因此
accountId
不会被映射。如果希望正确映射
accountId
,则必须发布类似于
{…,account:{id:1},}
的JSON



另一方面,将传输对象用于web服务的请求/响应对象,然后将这些对象映射到实体对象是一种相当常见的模式。然后,可以在传输对象中具有
accountId
属性,然后在组装实体时使用该值。这样做的一个原因可能是,例如,您不想从Web服务返回某些模型属性,也不想用
@JsonIgnore
注释污染模型层。这种方法还允许您更改实体类(例如重命名某些属性),而不必破坏API。然而,这将增加额外的复杂性,因此您必须决定是否值得这样做。

如果您使用jackson,还可以使用注释@JsonProperty

@OneToOne
@JoinColumn(name="accountId")
@JsonProperty("account")
private Account account;

这将把json属性帐户映射到您的帐户变量

,令人失望的是,这并不像我想象的那么简单。我回到了使用[@RequestBody String]并解析JSON来手动构建事务对象,这有点违背了这些端到端映射理想的目的。这种行为是正确的,
@RequestBody
对持久层一无所知,它只是将请求体映射到指定的对象。当您发布accountId时,它找不到它作为目标对象的属性(只有account),所以它会跳过它。也许您可以发布
{…,account:{id:1},…}
,在这种情况下,它应该映射到一个填写了id的空account对象。然后Hibernate实际上会在合并过程中基于该帐户查找实际帐户。虽然Hibernate没有实际查找Account对象,但我还没有测试它,但可以尝试一下。这解决了我的问题。它只是用提供的id创建了一个空帐户对象,该id足以生成正确的插入查询。你能把这个作为一个答案转发给我吗?如果我错了,请纠正我,但是如果你按照我的建议发布
{…,account:{id:1},…}
,那么它无论如何都会被映射,因为属性的名称相同(
account
),所以在这种情况下,
@JsonProperty
注释是不必要的。如果您发布
{…,accountId:1,…}
,那么
@JsonProperty
注释仍然不能确保accountId映射到Account类中的id字段,对吗?这是正确的Bohuslav-如果您想从json中接受不同于Account的名称,db需要join列,而@JsonProperty需要。很多时候,db字段名、类字段名和json值都是相同的。但我只是在用户希望使用不同于Json的值时抛出这个建议。就像Java中的所有东西一样,每件事都有大约10件事情要做,你的答案完全正确。我有点担心每个实体有2个类定义,我必须保持同步。我的架构目前还没有那么复杂,所以帐户:{id:1}建议就足够了。谢谢@我能理解。我曾经在一个有两个这样的层的项目中工作(一个用于SpringMVC表单的传输对象,一个用于在控制器和服务之间传输数据,根据这些数据在服务层上组装实体)。当您想要更改一个模型字段时,您必须更改实体、两个传输对象和三个映射器方法(实体->表单、表单->服务传输对象、服务传输对象->实体)。可以说,更改模型中的某些内容是一个相当漫长的过程:)