gpt4 book ai didi

java - 如何在部分更新PATCH Spring Boot MVC时自动添加Bean Validation

转载 作者:行者123 更新时间:2023-11-30 05:38:40 24 4
gpt4 key购买 nike

众所周知,实体的部分更新存在很大的问题。由于从json字符串到实体的自动转换,所有未传输的字段都会被标记为null。结果,我们不想重置的字段将被重置。

我将展示经典方案:

@RestController
@RequestMapping(EmployeeController.PATH)
public class EmployeeController {

public final static String PATH = "/employees";

@Autowired
private Service service;

@PatchMapping("/{id}")
public Employee update(@RequestBody Employee employee, @PathVariable Long id) {
return service.update(id, employee);
}
}

@Service
public class Service {

@Autowired
private EmployeeRepository repository;

@Override
public Employee update(Long id, Employee entity) {
Optional<T> optionalEntityFromDB = repository.findById(id);
return optionalEntityFromDB
.map(e -> saveAndReturnSavedEntity(entity, e))
.orElseThrow(RuntimeException::new);
}

private T saveAndReturnSavedEntity(Employee entity, Employee entityFromDB) {
entity.setId(entityFromDB.getId());
return repository.save(entity);
}
}

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}

正如我已经说过的,在当前的实现中,我们将无法以任何方式执行部分更新。也就是说,不可能只发送 json 行中一个字段的更新;所有字段都将被更新,并且为 null(已通过的除外)。

解决这个问题的方法是需要手动进行字符串json到实体的转换。也就是说,不要使用 Spring Boot 的所有魔力(这是非常可悲的)。

我还将给出一个示例,说明如何在 json 级别使用合并来实现这一点:

@RestController
@RequestMapping(EmployeeRawJsonController.PATH)
public class EmployeeRawJsonController {

public final static String PATH = "/raw-json-employees";

@Autowired
private EmployeeRawJsonService service;

@PatchMapping("/{id}")
public Employee update(@RequestBody String json, @PathVariable Long id) {
return service.update(id, json);
}
}

@Service
public class EmployeeRawJsonService {

@Autowired
private EmployeeRepository employeeRepository;

public Employee update(Long id, String json) {
Optional<Employee> optionalEmployee = employeeRepository.findById(id);
return optionalEmployee
.map(e -> getUpdatedFromJson(e, json))
.orElseThrow(RuntimeException::new);
}

private Employee getUpdatedFromJson(Employee employee, String json) {
Long id = employee.getId();

updateFromJson(employee, json);

employee.setId(id);
return employeeRepository.save(employee);
}

private void updateFromJson(Employee employee, String json) {
try {
new ObjectMapper().readerForUpdating(employee).readValue(json);
} catch (IOException e) {
throw new RuntimeException("Cannot update from json", e);
}
}
}

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}

通过此解决方案,我们消除了与部分更新相关的问题。

但是这里出现了另一个问题,我们失去了自动添加 Bean 验证的功能。

即第一种情况,验证添加一个注解@Valid即可:

@PatchMapping("/{id}")
public Employee update(@RequestBody @Valid Employee employee, @PathVariable Long id) {
return service.update(id, employee);
}

但是当我们执行手动反序列化时我们不能这样做。

我的问题是,有什么办法可以对第二种情况启用自动验证吗?或者也许还有其他解决方案允许您使用 Spring Boot 魔法进行 Bean 验证。

最佳答案

您需要的不是普通验证,这可以通过手动 validator 调用来实现。现在让我们走手动路线并以编程方式进行设置:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> violations = validator.validate(object);
for (ConstraintViolation<User> violation : violations) {
log.error(violation.getMessage());
}

要验证 bean,我们首先必须有一个 Validator 对象,该对象是使用 ValidatorFactory 构造的。

在处理请求时,在 DataBinding 阶段会自动触发使用 @Valid 注解指定的 Spring Controller 上的正常验证。所有在 DataBinder 中注册的 validator 都将在该阶段执行。我们无法针对您的情况执行此操作,因此您可以像上面一样手动触发验证。

关于java - 如何在部分更新PATCH Spring Boot MVC时自动添加Bean Validation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56139024/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com