PUT场景实现Json对象部分赋值

231 阅读2分钟

场景

假设我们有一个User实体类

public class UserDTO {
    
    private String username;
    
    private Integer age;

    private String address;
}

我们有一个PUT接口来对用户进行部分字段更新

我们希望当请求体Json如下时,仅更新address为shanghai

{
  "address": "shanghai"
}

这显然很简单,然而,我们希望当请求体Json如下时,仅更新age为null

{
  "age": null
}

我们的UserDTO无法分辨age是否被赋值,因此需要对age进行状态管理,有如下3种方法

1. 使用默认值

我们可以对DTO稍加改造,针对需要的字段添加默认值

public class UserDTO {
    
    private String username;
    
    private Integer age = DEFAULT_AGE;

    private String address = DEFAULT_ADDRESS;
}

然后在业务代码中判断是否是默认值,就可以知道该字段是未赋值,还是赋值为null

这种方法可以解决大部分的场景,但是存在一个缺点,即默认值的存在相当于是一个漏洞,当我们需要添加校验规则时,就必须绕过这个默认值。

2. 状态管理

当然,我们也可以在setter上做文章,如下,我们给age字段加了个ageIsSet的状态字段,并且在setAge中对ageIsSet赋值true

public class UserDTO {

    private String username;

    private Integer age;

    private boolean ageIsSet = false;

    public void setAge(Integer age) {
        this.ageIsSet = true;
        this.age = age;
    }

    private String address;
}

当Json中存在字段时,Jackson等工具会通过setter赋值,就可以知道该字段是否赋值

这种方法的缺点就是会造成字段膨胀,而且可能需要在一些地方忽略这些状态字段,也相当不优雅。

3. 使用Optional

使用Optional,就相当于扩展出了一种状态--empty

public class UserDTO {

    private String username;

    private Optional<Integer> age;

    public void setAge(Integer age) {
        this.age = Optional.ofNullable(age);
    }

    private String address;
}

当Json中不存在age时,age为null

当Json中的age为null时,age为Optional.empty()

这样,我们可以通过age==null来判断是否赋值,然后再通过age.orElse(null)来取值。

并且,Bean Validation支持校验Optional类型,示例如下:

    private Optional<@Min(0) @Max(100) Integer> age;