Spring PATCH 请求中的部分 bean 验证

Spring partial bean validation in PATCH request

我正在制作 Spring 启动应用程序。我在那里有一个实体:

@Entity
public class Employee {
    @NotNull
    private Category category;

    // Education related fields
    @NotNull
    private Education education;
    @NotBlank
    private String eduName;
    @NotNull
    private LocalDate eduGraduationDate;

    // other fields, getters, setters ...
}

如您所见,我在那里有验证注释。但是在我的应用程序中,我需要部分更新字段,例如客户想要与 Category 字段分开更新 Education 字段。

问题是我不能使用 PUT 请求来执行此操作,因为它会更新整个对象。如果 Category 字段实际上是 null,而我只想更新 Education 字段,我将得到 ConstraintViolationException,因为 Category 字段是 null。但它是 null,我希望它更进一步 null

我可以使用 PATCH 请求来执行此操作:

@PatchMapping(path = "/{id}", consumes = "application/merge-patch+json")
public ResponseEntity<Employee> patchEmployee(@PathVariable Long id, @RequestBody JsonMergePatch jsonMergePatch) throws JsonPatchException, JsonProcessingException {
    Employee employee = employeeDataService.findById(id).orElseThrow(() -> new ResourceNotFoundException("Employee not exist: id = " + id));
        
    Employee employeePatched = applyPatchToEmployee(jsonMergePatch, employee);

    return ResponseEntity.ok(employeeDataService.save(employeePatched));
}
    
private Employee applyPatchToEmployee(JsonMergePatch jsonMergePatch, Employee targetEmployee) throws JsonPatchException, JsonProcessingException {
    JsonNode patched = jsonMergePatch.apply(objectMapper.convertValue(targetEmployee, JsonNode.class));
    return objectMapper.treeToValue(patched, Employee.class);
}

但问题是:我如何才能部分验证我的字段?

例如,如果我发送一个正文为 PATCH 的请求:

{
    "education":"HIGHER",
    "eduName":"MIT",
    "eduGraduationDate":"2020-05-05"
}

如何只验证这 3 个字段?不是整个 Employee 对象?在这个例子中,正如我上面提到的,我希望 Category 字段是 null 并且我不想验证它,如果它不包含在补丁中。

也许有一些更好的方法来部分更新实体,如果是的话 - 哪个?

您可以创建一个新的 DTO 对象,其中仅包含您希望包含在 PATCH 调用中的字段,例如,

EmployeePatchDto

public class EmployeePatchDto {

    // Education related fields
    @NotNull
    private Education education;
    @NotBlank
    private String eduName;
    @NotNull
    private LocalDate eduGraduationDate;

    // other fields, getters, setters ...
}

但现在您仍然需要确保在调用 API 时考虑这些验证。 此外,您可以选择使用 @Valid 在控制器方法级别验证您的 DTO class,

public ResponseEntity<Employee> patchEmployee(@PathVariable Long id, @Valid @RequestBody EmployeePatchDto employeeDto) throws JsonPatchException, JsonProcessingException {

我把这个资源留给你。 Read this.