9

在我的 Spring Boot 服务中,我使用https://github.com/java-json-tools/json-patch来处理 PATCH 请求。

除了避免修改对象 id、creation_time 等不可变字段的方法外,一切似乎都很好。我在 Github https://github.com/java-json-tools/json-patch/issues/21上发现了一个类似的问题我找不到正确的例子。

这个博客似乎提供了一些关于使用 node.js 中的解决方案验证 JSON 补丁请求的有趣解决方案。很高兴知道 JAVA 中是否已经存在类似的东西。

4

2 回答 2

9

在许多情况下,您可以只修补一个只有用户可以写入的字段的中间对象。之后,您可以使用一些对象映射器或手动将中间对象轻松映射到您的实体。

这样做的缺点是,如果您要求字段必须显式可为空,您将不知道补丁对象是否将字段显式设置为空,或者它是否从未出现在补丁中。

您也可以为此滥用 Optionals,例如

public class ProjectPatchDTO {

    private Optional<@NotBlank String> name;
    private Optional<String> description;
}

尽管 Optionals 不打算像这样使用,但它是在保持类型化输入的同时实现补丁操作的最直接的方法。当可选字段为空时,它永远不会从客户端传递。当可选项不存在时,这意味着客户端已将该值设置为空。

于 2018-05-11T16:25:40.217 回答
0

不要直接从客户端接收 a ,而是JsonPatch定义一个 DTO 来处理验证,然后您稍后会将 DTO 实例转换为JsonPatch.

假设您要更新 instance 的用户User.class,您可以定义一个 DTO,例如:

public class UserDTO {

    @Email(message = "The provided email is invalid")
    private String username;

    @Size(min = 2, max = 10, message = "firstname should have at least 2 and a maximum of 10 characters")
    private String firstName;

    @Size(min = 2, max = 10, message = "firstname should have at least 2 and a maximum of 10 characters")
    private String lastName;

    @Override
    public String toString() {
        return new Gson().toJson(this);
    }

//getters and setters
}

自定义toString方法确保更新请求中未包含的字段不会预填充null值。

您的PATCH要求可以如下(为简单起见,我没有迎合例外)

@PatchMapping("/{id}")
    ResponseEntity<Object> updateUser(@RequestBody @Valid UserDTO request,
                                      @PathVariable String id) throws ParseException, IOException, JsonPatchException {
        User oldUser = userRepository.findById(id);
        String detailsToUpdate = request.toString();
        User newUser = applyPatchToUser(detailsToUpdate, oldUser);
        userRepository.save(newUser);
        return userService.updateUser(request, id);
    }

以下方法返回上面在控制器中更新的修补用户。

private User applyPatchToUser(String detailsToUpdate, User oldUser) throws IOException, JsonPatchException {
        ObjectMapper objectMapper = new ObjectMapper();
        // Parse the patch to JsonNode
        JsonNode patchNode = objectMapper.readTree(detailsToUpdate);
        // Create the patch
        JsonMergePatch patch = JsonMergePatch.fromJson(patchNode);
        // Convert the original object to JsonNode
        JsonNode originalObjNode = objectMapper.valueToTree(oldUser);
        // Apply the patch
        TreeNode patchedObjNode = patch.apply(originalObjNode);
        // Convert the patched node to an updated obj
        return objectMapper.treeToValue(patchedObjNode, User.class);
    }
于 2022-01-06T20:19:42.697 回答