2017-07-19 38 views
1

我试图实现基于下面的经理实体的部分更新:与@PATCH方法弹簧安置部分更新

实体

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

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

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

回答

1

你可以写一个只更新特定字段的自定义更新查询:

@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(); 
} 
+0

它运作良好,但在这种情况下是不相关的使用POST和补丁,右? – wilson

+0

这取决于你的需求。在我看来,最好使用PUT(或POST)进行修改 –

1

首先,你需要知道,如果你正在做的插入或更新。插入很简单。在更新时,使用get()来检索实体。然后更新任何字段。在事务结束时,Hibernate将刷新更改并提交。

1

如果您确实在使用PATCH,则应该使用RequestMethod.PATCH,而不是RequestMethod.POST。

您的修补程序映射应该包含您可以检索要修补的管理器对象的标识。此外,它应该只包含您想要更改的字段。在你的例子中,你发送的是整个实体,所以你无法辨别实际上正在改变的字段(空的意思是单独离开这个字段,还是实际上改变它的值为空)。

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

@RequestMapping(value = "/manager/{id}", method = RequestMethod.PATH) 
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 k 
     Field field = ReflectionUtils.findField(Manager.class, k); 
     ReflectionUtils.setField(field, manager, v); 
    }); 
    managerService.saveManager(manager); 
} 
+0

当RequestBody是纯文本形式时,这种方法是什么?你使用转换器从纯文本转换为地图吗? – blaa

1

有了这个,你可以修补的变化

1. Autowire `ObjectMapper` in controller; 

2. @PatchMapping("/manager/{id}") 
    ResponseEntity<?> saveManager(@RequestBody Map<String, String> manager) { 
     Manager toBePatchedManager = objectMapper.convertValue(user, 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(); 
}