如何使用 Spring MVC 忽略我的 DTO 对象中缺少的属性?
How can I ignore missing properties in my DTO objects with Spring MVC?
我们正在使用 Spring MVC 4
。
假设我有一个名为 Customer
的实体。该实体有几个属性,有些允许空值,有些则不允许。
我们还使用了一个 DTO
对象 (CustomerDTO
),它通过 @RequestBody
.
从远程客户端传递到我们的 @RestController
这是我遇到的问题。假设用户通过 PUT
:
输入以下内容
{
"id": 123,
"name": "ACME",
"desc": "Blah"
}
一切都很好。但是如果用户只想更新 name
,他们会传入:
{
"id": 123,
"name": "ACME 2"
}
客户现在在允许的 desc
中有一个 null
。
所以我的问题是,如果 Spring/Hibernate 没有传递到 DTO,我怎样才能让 desc
甚至不把 desc
放在更新语句中?
我认为问题在于 Spring 将以下内容视为同一件事:
{
...
"desc": null,
...
}
{
...
... <desc omitted>
}
谢谢
基于Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?,看来您基本上有 2 个可行的选择:
- 从数据库中读取实体并更新特定字段
- 使用
@SessionAttibutes
您可以使用 Blaze-Persistence Updatable Entity Views,而不是通过单独加载实体状态来实现它,这是一个用于在 JPA 之上开发 DTO 的库,它还实现了对乐观锁定的支持。
你的用例应该已经得到支持,虽然我还没有很好的 Spring WebMvc 集成,所以你现在必须自己做一些管道。不过,我对此有一些想法,这只是时间问题和感兴趣的各方,直到集成更加顺利。
可更新的实体视图允许映射实体的子集,并且也只刷新该子集。由于使用脏跟踪,它确切地知道发生了什么变化,允许细粒度的刷新。
因此 PATCH 支持 的想法就是通过对象的 id 获取空引用。为空意味着它没有数据,即所有空值。脏跟踪假定初始状态为空。您可以简单地将请求有效负载映射到此对象,如果值为空,它不会将其识别为已更改,因此将其忽略。如果设置了任何非空值,它确定这样的字段是脏的并且在刷新时,仅刷新脏值。
我自己还没有尝试过,但你可以这样做
// Create reference for the id, the object is empty i.e. all null except for the id
CustomerDTO dto = entityViewManager.getReference(CustomerDTO.class, someId);
// Map the payload on the DTO which will call setFoo(null) but that's ok, because that isn't considered being dirty
jsonMapper.map(requestPayload, dto);
// Flush dirty changes i.e. non-null values
entityViewManager.update(entityManager, dto);
使用 PARTIAL
刷新模式时执行的更新查询将只包含具有非空值的属性的 set 子句。 DTO 看起来像这样
@EntityView(Customer.class)
@UpdatableEntityView(mode = FlushMode.PARTIAL)
public interface CustomerDTO {
@IdMapping Integer getId();
String getName();
void setName(String name);
String getDesc();
void setDesc(String desc);
}
如果没有脏东西,它甚至不会执行查询。
我们正在使用 Spring MVC 4
。
假设我有一个名为 Customer
的实体。该实体有几个属性,有些允许空值,有些则不允许。
我们还使用了一个 DTO
对象 (CustomerDTO
),它通过 @RequestBody
.
@RestController
这是我遇到的问题。假设用户通过 PUT
:
{
"id": 123,
"name": "ACME",
"desc": "Blah"
}
一切都很好。但是如果用户只想更新 name
,他们会传入:
{
"id": 123,
"name": "ACME 2"
}
客户现在在允许的 desc
中有一个 null
。
所以我的问题是,如果 Spring/Hibernate 没有传递到 DTO,我怎样才能让 desc
甚至不把 desc
放在更新语句中?
我认为问题在于 Spring 将以下内容视为同一件事:
{
...
"desc": null,
...
}
{
...
... <desc omitted>
}
谢谢
基于Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?,看来您基本上有 2 个可行的选择:
- 从数据库中读取实体并更新特定字段
- 使用
@SessionAttibutes
您可以使用 Blaze-Persistence Updatable Entity Views,而不是通过单独加载实体状态来实现它,这是一个用于在 JPA 之上开发 DTO 的库,它还实现了对乐观锁定的支持。 你的用例应该已经得到支持,虽然我还没有很好的 Spring WebMvc 集成,所以你现在必须自己做一些管道。不过,我对此有一些想法,这只是时间问题和感兴趣的各方,直到集成更加顺利。
可更新的实体视图允许映射实体的子集,并且也只刷新该子集。由于使用脏跟踪,它确切地知道发生了什么变化,允许细粒度的刷新。
因此 PATCH 支持 的想法就是通过对象的 id 获取空引用。为空意味着它没有数据,即所有空值。脏跟踪假定初始状态为空。您可以简单地将请求有效负载映射到此对象,如果值为空,它不会将其识别为已更改,因此将其忽略。如果设置了任何非空值,它确定这样的字段是脏的并且在刷新时,仅刷新脏值。
我自己还没有尝试过,但你可以这样做
// Create reference for the id, the object is empty i.e. all null except for the id
CustomerDTO dto = entityViewManager.getReference(CustomerDTO.class, someId);
// Map the payload on the DTO which will call setFoo(null) but that's ok, because that isn't considered being dirty
jsonMapper.map(requestPayload, dto);
// Flush dirty changes i.e. non-null values
entityViewManager.update(entityManager, dto);
使用 PARTIAL
刷新模式时执行的更新查询将只包含具有非空值的属性的 set 子句。 DTO 看起来像这样
@EntityView(Customer.class)
@UpdatableEntityView(mode = FlushMode.PARTIAL)
public interface CustomerDTO {
@IdMapping Integer getId();
String getName();
void setName(String name);
String getDesc();
void setDesc(String desc);
}
如果没有脏东西,它甚至不会执行查询。