Java 如何使用SpringMVC忽略DTO对象中缺少的属性?

Java 如何使用SpringMVC忽略DTO对象中缺少的属性?,java,hibernate,spring-mvc,dto,Java,Hibernate,Spring Mvc,Dto,我们正在使用springmvc4 假设我有一个名为Customer的实体。该实体具有多个属性,其中一些属性允许空值,而另一些属性不允许空值 我们还使用一个DTO对象(CustomerDTO),该对象通过@RequestBody从远程客户端传递到我们的@RestController) 这是我的问题。假设用户通过PUT传入以下内容: { "id": 123, "name": "ACME", "desc": "Blah" } 一切都很好。但如果用户只想更新名称,则会传入: {

我们正在使用
springmvc4

假设我有一个名为
Customer
的实体。该实体具有多个属性,其中一些属性允许空值,而另一些属性不允许空值

我们还使用一个
DTO
对象(
CustomerDTO
),该对象通过
@RequestBody
从远程客户端传递到我们的
@RestController

这是我的问题。假设用户通过
PUT
传入以下内容:

{
    "id": 123,
    "name": "ACME",
    "desc": "Blah"
}
一切都很好。但如果用户只想更新
名称
,则会传入:

{
    "id": 123,
    "name": "ACME 2"
}
客户现在在
desc
中有一个
null
,这是允许的

所以我的问题是,如果Spring/Hibernate没有被传递到DTO中,我怎么能让它不在update语句中添加
desc

我认为,问题在于Spring将以下内容视为同一件事:

{
    ...
    "desc": null,
    ...
}

{
    ...
    ...   <desc omitted>
}
{
...
“desc”:空,
...
}
{
...
...   
}
谢谢

基于,您似乎基本上有两个可行的选择:

  • 从数据库中读取实体并更新特定字段
  • 使用

  • 您不需要单独加载实体状态来实现这一点,而是可以利用实体状态库在JPA之上开发DTO,该库还实现了对乐观锁定的支持。 您的用例应该已经得到支持,尽管我还没有一个很好的SpringWebMVC集成,所以您现在必须自己做一些管道工作。我有一些想法,不过,这只是一个时间问题和利益相关方,直到整合将更加顺利

    可更新的实体视图允许映射实体的子集,并且只刷新该子集。由于使用了脏跟踪,它准确地知道发生了什么变化,从而允许细粒度的刷新

    因此,补丁支持的想法,也就是您在这里想要的,就是只获取一个对象的id的空引用。为空意味着它没有数据,即所有空值。脏跟踪假设初始状态全部为空。您可以简单地将一个请求负载映射到这个对象上,如果一个值为null,它将不会识别它正在被更改,因此忽略它。如果设置了任何非null值,它将确定此类字段为脏字段,并且在刷新时,仅刷新脏值

    我自己还没试过,但你可以这样做

    // 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);
    
    @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);
    }
    
    使用
    PARTIAL
    flush模式时执行的更新查询将仅包含具有非空值的属性的set子句。DTO看起来像这样

    // 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);
    
    @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);
    }
    
    如果没有脏东西,它甚至不会执行查询。

    可能重复的