使用@PATCH方法进行弹簧REST部分更新

2022-09-03 16:25:10

我正在尝试实现基于以下内容的管理器实体的部分更新:

实体

public class Manager {
    private int id;
    private String firstname;
    private String lastname;
    private String username;
    private String password;

    // getters and setters omitted
}

控制器中的保存管理器方法

@RequestMapping(value = "/save", method = RequestMethod.PATCH)
public @ResponseBody void saveManager(@RequestBody Manager manager){
    managerService.saveManager(manager);
}

在 Dao impl 中保存对象管理器。

@Override
public void saveManager(Manager manager) {  
    sessionFactory.getCurrentSession().saveOrUpdate(manager);
}

当我保存对象时,用户名和密码已更改正确,但其他值为空。

因此,我需要做的是更新用户名和密码并保留所有剩余数据。


答案 1

如果你真的在使用 PATCH,那么你应该使用 RequestMethod.PATCH,而不是 RequestMethod.POST。

修补程序映射应包含可用于检索要修补的 Manager 对象的 ID。此外,它应仅包含要更改的字段。在您的示例中,您正在发送整个实体,因此您无法辨别实际更改的字段(空是否意味着保留此字段或实际上将其值更改为空)。

也许这样的实现是你所追求的?

@RequestMapping(value = "/manager/{id}", method = RequestMethod.PATCH)
public @ResponseBody void saveManager(@PathVariable Long id, @RequestBody Map<Object, Object> fields) {
    Manager manager = someServiceToLoadManager(id);
    // Map key is field name, v is value
    fields.forEach((k, v) -> {
       // use reflection to get field k on manager and set it to value v
        Field field = ReflectionUtils.findField(Manager.class, k);
        field.setAccessible(true);
        ReflectionUtils.setField(field, manager, v);
    });
    managerService.saveManager(manager);
}

答案 2

这样,您就可以修补更改

1. Autowire `ObjectMapper` in controller;

2. @PatchMapping("/manager/{id}")
    ResponseEntity<?> saveManager(@RequestBody Map<String, String> manager) {
        Manager toBePatchedManager = objectMapper.convertValue(manager, Manager.class);
        managerService.patch(toBePatchedManager);
    }

3. Create new method `patch` in `ManagerService`

4. Autowire `NullAwareBeanUtilsBean` in `ManagerService`

5. public void patch(Manager toBePatched) {
        Optional<Manager> optionalManager = managerRepository.findOne(toBePatched.getId());
        if (optionalManager.isPresent()) {
            Manager fromDb = optionalManager.get();
            // bean utils will copy non null values from toBePatched to fromDb manager.
            beanUtils.copyProperties(fromDb, toBePatched);
            updateManager(fromDb);
        }
    }

您必须扩展以实现非空值行为的复制。BeanUtilsBean

public class NullAwareBeanUtilsBean extends BeanUtilsBean {

    @Override
    public void copyProperty(Object dest, String name, Object value)
            throws IllegalAccessException, InvocationTargetException {
        if (value == null)
            return;
        super.copyProperty(dest, name, value);
    }
}

最后,将 NullAwareBeanUtilsBean 标记为@Component

注册为豆类NullAwareBeanUtilsBean

@Bean
public NullAwareBeanUtilsBean nullAwareBeanUtilsBean() {
    return new NullAwareBeanUtilsBean();
}