Java 使用@PATCH方法对弹簧座进行部分更新
我正在尝试基于以下内容对Manager实体进行部分更新: 实体Java 使用@PATCH方法对弹簧座进行部分更新,java,spring,rest,Java,Spring,Rest,我正在尝试基于以下内容对Manager实体进行部分更新: 实体 public class Manager { private int id; private String firstname; private String lastname; private String username; private String password; // getters and setters omitted } 控制器中的SaveManager方法
public class Manager {
private int id;
private String firstname;
private String lastname;
private String username;
private String password;
// getters and setters omitted
}
控制器中的SaveManager方法
@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);
}
保存对象时,用户名和密码已正确更改,但其他值为空
因此,我需要做的是更新用户名和密码并保留所有剩余数据。您可以编写自定义更新查询,只更新特定字段:
@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();
}
首先,您需要知道您是在执行插入还是更新。插入很简单。更新时,使用get()检索实体。然后更新所有字段。事务结束时,Hibernate将刷新更改并提交。如果您确实在使用修补程序,则应使用RequestMethod.PATCH,而不是RequestMethod.POST 修补程序映射应包含可用于检索要修补的Manager对象的id。此外,它应该只包括要更改的字段。在您的示例中,您发送的是整个实体,因此无法识别实际正在更改的字段(empty是指不处理此字段还是实际将其值更改为空) 也许您所追求的就是这样一个实现
@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);
}
@RequestMapping(value=“/manager/{id}”,method=RequestMethod.PATCH)
public@ResponseBody void saveManager(@PathVariable Long id,@RequestBody映射字段){
Manager Manager=someServiceToLoadManager(id);
//映射键是字段名,v是值
字段。forEach((k,v)->{
//使用反射获取管理器上的字段k,并将其设置为值v
Field=ReflectionUtils.findField(Manager.class,k);
字段。setAccessible(true);
ReflectionUtils.setField(字段,管理器,v);
});
managerService.saveManager(manager);
}
使用此功能,您可以修补更改
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);
}
}
最后,将null标记为@Component
或
将NullAwareBeanUtilsBean
注册为bean
@Bean
public NullAwareBeanUtilsBean nullAwareBeanUtilsBean() {
return new NullAwareBeanUtilsBean();
}
它工作得很好,但在这种情况下与使用POST和PATCH无关,对吗?这取决于您的需要。在我看来,最好使用PUT(或POST)进行修改,当RequestBody是纯文本形式时,该方法是什么?您是否使用转换器将纯文本转换为地图?@lane.maxwell Ya如果我们使用RequestMethod.PATCH,我完全同意您的回答,那么我们需要使用地图,但我有一些困惑,请您清除它好吗?,若我改变了方法类型补丁,将所有的更改保持原样,那个么它对数据库的作用是相同的,那个么它是如何不同的。我知道PUT和PATCH-1有两个区别。如果不存在,请创建新条目。2.仅更改特定值,而不是整个JSON。对于JPA来说,它有用吗?是的,那么怎么做呢?@DhwanilPatel从你的代码和它的行为的角度来看,PUT、PATCH甚至POST的行为都是一样的。为了遵守HTTP规范,PUT请求应该包含整个实体,而补丁将只包含您要修改的属性。感谢您的解决方案。但是当我没有在'findField'和'setField'之间编写命令:“field.setAccessible(true);”时,我遇到了InvocationTargetException。希望它能帮助一些人。这是一个很好的评论,因为setField假设字段是可访问的。我要修改答案“user”来自哪里,它是什么?@Boris My bad,它应该是
manager
param。更正了代码。那么,如果我们真的想将字段值更改为NULL呢!从BeanAwareNullUtilsGood Response中删除“value==null”检查。更简单的是,BeanUtilsBean
的文档说明:如果源“bean”实际上是一个映射,则假定它包含字符串值的简单属性名作为键,指向将被转换(如有必要)并在目标bean中设置的相应属性值。也就是说,可以跳过Jackson部分和NullAwareBeanUtilsBean部分。只需使用BeanUtilsBean.getInstance().copyProperties(fromDb,manager)代码>。我在这篇文章中总结了一些关于如何使用补丁的详细信息。这篇文章中描述的方法在GitHub上可用。
@Bean
public NullAwareBeanUtilsBean nullAwareBeanUtilsBean() {
return new NullAwareBeanUtilsBean();
}