Java 用于使用空值或空值更新信息的REST API

Java 用于使用空值或空值更新信息的REST API,java,rest,jackson,resteasy,Java,Rest,Jackson,Resteasy,我有一个关于如何最好地构建能够修改数据库中记录的API的一般性问题 假设我们有一个包含10列的表,我们可以使用REST(GET)查询这10列。JSON响应将包含所有10个字段。这是很容易的,工作没有问题 下一步是有人想通过POST创建新记录。在这种情况下,此人只发送JSON请求中10个字段中的8个。然后,我们将只填充数据库中的8个字段(其余字段将为空)。这也没有问题 但是如果有人想要更新记录,会发生什么呢?我们在这里看到了各种各样的可能性,有优缺点 只发送应该更新的内容。 问题:如何显式清空/删

我有一个关于如何最好地构建能够修改数据库中记录的API的一般性问题

假设我们有一个包含10列的表,我们可以使用REST(GET)查询这10列。JSON响应将包含所有10个字段。这是很容易的,工作没有问题

下一步是有人想通过POST创建新记录。在这种情况下,此人只发送JSON请求中10个字段中的8个。然后,我们将只填充数据库中的8个字段(其余字段将为空)。这也没有问题

但是如果有人想要更新记录,会发生什么呢?我们在这里看到了各种各样的可能性,有优缺点

  • 只发送应该更新的内容。 问题:如何显式清空/删除字段?如果在JSON中传递了一个“NULL”,那么我们在对象中得到NULL,但是任何其他未传递的字段也都是NULL。因此,我们无法区分哪些字段可以删除,哪些字段不能触摸

  • 发送完整的对象。 问题:在这里,对象可以通过GET-before获取,相应地更改,然后通过PUT返回。现在我们得到了所有的信息,可以直接将信息写回数据库。因为空字段之前已为空,或者已被用户清除

  • 如果对象通过API的更新进行扩展,会发生什么情况。假设我们将数据库再扩展五个字段。API的用户做了一个GET,得到了15个字段,但只能读取他在页面上知道的10个字段(因为他还没有更新自己的页面)。然后,他更改了10个字段中的一些字段,并通过PUT将它们发送回。然后,我们将只更新网站上的10个字段,并从数据库中清空5个新字段

    还是必须为每个字段创建单独的端点?我们还考虑过创建一个带有键/值的映射,具体应该更改什么

    关于技术:我们将Wildfly 15与Resteasy和Jackson一起使用

    例如:

    开始时的数据库

    +----+----------+---------------+-----+--------+-------+
    | ID | Name     | Country       | Age | Weight | Phone |
    +----+----------+---------------+-----+--------+-------+
    | 1  | Person 1 | Germany       | 22  | 60     | 12345 |
    | 2  | Person 2 | United States | 32  | 78     | 56789 |
    | 3  | Person 3 | Canada        | 52  | 102    | 99999 |
    +----+----------+---------------+-----+--------+-------+
    
    获取…/人/2

    {
       "id" : 2,
       "name" : "Person 2",
       "country" : "United States",
       "age" : 22,
       "weight" :62,
       "phone": "56789"
    }
    
    {
       "id" : 2,
       "name" : "Person 2",
       "country" : "United States",
       "age" : 22,
       "weight" :78
    }
    
    现在我想更新他的体重,去掉电话号码

    放…/人/2

    {
       "id" : 2,
       "name" : "Person 2",
       "country" : "United States",
       "age" : 22,
       "weight" :62,
       "phone": "56789"
    }
    
    {
       "id" : 2,
       "name" : "Person 2",
       "country" : "United States",
       "age" : 22,
       "weight" :78
    }
    

    现在,数据库应该如下所示:

    +----+----------+---------------+-----+--------+-------+
    | ID | Name     | Country       | Age | Weight | Phone |
    +----+----------+---------------+-----+--------+-------+
    | 1  | Person 1 | Germany       | 22  | 60     | 12345 |
    | 2  | Person 2 | United States | 32  | 78     | NULL  |
    | 3  | Person 3 | Canada        | 52  | 102    | 99999 |
    +----+----------+---------------+-----+--------+-------+
    
    问题是

    我们这样扩展桌子(萨利里)

    使用API的人不知道JSON中有一个新的工资字段。此人现在想再次更改某人的电话号码,但不发送工资。这也将清空工资:

    {
       "id" : 3,
       "name" : "Person 3",
       "country" : "Cananda",
       "age" : 52,
       "weight" :102,
       "phone" : null
    }
    
    
    +----+----------+---------------+-----+--------+--------+-------+
    | ID | Name     | Country       | Age | Weight | Salery | Phone |
    +----+----------+---------------+-----+--------+--------+-------+
    | 1  | Person 1 | Germany       | 22  | 60     | 1929   | 12345 |
    | 2  | Person 2 | United States | 32  | 78     | 2831   | NULL  |
    | 3  | Person 3 | Canada        | 52  | 102    | NULL   | NULL  |
    +----+----------+---------------+-----+--------+--------+-------+
    

    工资不应为空,因为它不是在JSON请求中设置的

    一种常见的技术是跟踪实体POJO上的更改

  • 颜色
    =黑色、
    大小
    =空值和
    年龄
    =空值加载狗
  • size
    设置为null(设置程序将此字段标记为已更改)
  • 运行更新SQL

  • POJO将有一个内部状态,知道
    大小
    已更改,因此将该字段包括在更新中<另一方面,代码>年龄从未设置,因此保持不变。jOOQ就是这样工作的,我相信还有其他的。

    您可以如下控制空值或空值

    public class Person{
    
        @JsonInclude(JsonInclude.Include.NON_NULL) 
        private BigDecimal salary;  // this will make sure salary can't be null or empty//
    
        private String phone;   //allow phone Number to be empty
        // same logic for other fields
    }
    
    i) 当您更新重量和删除电话号码时,请客户机发送需要更新的字段以及记录标识符(在本例中为id)

    {
       "id" : 2,
       "weight" :78,
       "phone" : null  
    }
    
    ii)由于您将工资添加为一个额外的列,这是必填字段,客户应该知道。您可能需要重新设计合同

  • 只发送应该更新的内容。问题:如何显式清空/删除字段?如果在JSON中传递了一个“NULL”,那么我们在对象中得到NULL,但是任何其他未传递的字段也都是NULL。因此,我们无法区分哪些字段可以删除,哪些字段不能触摸
  • 你发现的问题是真实的;我也面对过这个问题。我认为,为此提供技术解决方案是合理的,而是记录API的使用情况,让调用者知道省略字段或以
    null
    的形式发送字段的影响。当然,假设服务器端的验证是严格的,并且确保了完整性

  • 发送完整的对象。问题:在这里,对象可以通过GET-before获取,相应地更改,然后通过PUT返回。现在我们得到了所有的信息,可以直接将信息写回数据库。因为空字段之前已为空,或者已被用户清除
  • 这是“更直截了当的”,应该记录在API中

    如果对象通过API的更新进行扩展,会发生什么情况

    通过文档将责任交给调用方,这也是隐式处理的

    还是必须为每个字段创建单独的端点

    这也是一个设计问题,解决方案因人而异。我宁愿将API保留在记录级别,而不是单个值级别。然而,在某些情况下,可能需要这样做。例如,状态更新

    假设我们将数据库再扩展五个字段。API的用户做了一个GET,得到了15个字段,但只能读取他在页面上知道的10个字段(因为他还没有更新自己的页面)。然后,他更改了10个字段中的一些字段,并通过PUT将它们发送回。然后,我们将只更新网站上的10个字段,并从数据库中清空5个新字段

    让我们从一个例子开始——在web上会发生什么,客户机通过浏览器中呈现的HTML与API交互。客户端将获得一个表单,该表单将为每个字段提供输入控件。客户端更新表单中的字段,提交表单,然后将这些更改应用到数据库中

    当您想要扩展
      ObjectMapper mapper = new ObjectMapper();
      TypeReference<HashMap<String, Object>> typeReference = new TypeReference<>() {};
      HashMap<String, Object> jsonMap = mapper.readValue(json, typeReference);
      jsonMap.entrySet().stream().map(Map.Entry::getKey).forEach(System.out::println);
    
    data class PlacementRequestDto(
        val contentId: Int,
        @param:JsonProperty(required = true)
        val tlxPlacementId: Int?,
        val keywords: List<Int>,
        val placementAdFormats: List<Int>
    )