Java 使用@PATCH 方法进行 Spring REST 部分更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45200142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:53:25  来源:igfitidea点击:

Spring REST partial update with @PATCH method

javaspringrest

提问by wilson

I'm trying to implement a partial update of the Manager entity based in the following:

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

Entity

实体

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

    // getters and setters omitted
}

SaveManager method in Controller

控制器中的 SaveManager 方法

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

Save object manager in Dao impl.

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

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

When I save the object the username and password has changed correctly but the others values are empty.

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

So what I need to do is update the username and password and keep all the remaining data.

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

采纳答案by Mykola Yashchenko

You can write custom update query which updates only particular fields:

您可以编写仅更新特定字段的自定义更新查询:

@Override
public void saveManager(Manager manager) {  
    Query query = sessionFactory.getCurrentSession().createQuery("update Manager set username = :username, password = :password where id = :id");
    query.setParameter("username", manager.getUsername());
    query.setParameter("password", manager.getPassword());
    query.setParameter("id", manager.getId());
    query.executeUpdate();
}

回答by Steve11235

First, you need to know if you are doing an insert or an update. Insert is straightforward. On update, use get() to retrieve the entity. Then update whatever fields. At the end of the transaction, Hibernate will flush the changes and commit.

首先,您需要知道您是在执行插入操作还是更新操作。插入很简单。更新时,使用 get() 检索实体。然后更新任何字段。在事务结束时,Hibernate 将刷新更改并提交。

回答by lane.maxwell

If you are truly using a PATCH, then you should use RequestMethod.PATCH, not RequestMethod.POST.

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

Your patch mapping should contain the id with which you can retrieve the Manager object to be patched. Also, it should only include the fields with which you want to change. In your example you are sending the entire entity, so you can't discern the fields that are actually changing (does empty mean leave this field alone or actually change its value to empty).

您的补丁映射应包含可用于检索要修补的 Manager 对象的 ID。此外,它应该只包含您想要更改的字段。在您的示例中,您正在发送整个实体,因此您无法辨别实际发生变化的字段(空是否意味着不理会该字段或实际将其值更改为空)。

Perhaps an implementation as such is what you're after?

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

@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);
        ReflectionUtils.setField(field, manager, v);
    });
    managerService.saveManager(manager);
}

回答by Yogesh Badke

With this, you can patch your changes

有了这个,您可以修补您的更改

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);
        }
    }

You will have to extend BeanUtilsBeanto implement copying of non null values behaviour.

您将不得不扩展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);
    }
}

and finally, mark NullAwareBeanUtilsBean as @Component

最后,将 NullAwareBeanUtilsBean 标记为 @Component

or

或者

register NullAwareBeanUtilsBeanas bean

注册NullAwareBeanUtilsBean为bean

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