Spring 部分更新对象数据绑定 [英] Spring Partial Update Object Data Binding

查看:20
本文介绍了Spring 部分更新对象数据绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试在 Spring 3.2 中实现一个特殊的部分更新功能.我们在后端使用 Spring,并有一个简单的 Javascript 前端.我无法找到满足我们需求的直接解决方案,即update() 函数应该接受任意数量的 field:values 并相应地更新持久性模型.

我们对所有字段进行了内嵌编辑,因此当用户编辑一个字段并确认时,一个 id 和修改后的字段会作为 json 传递给控制器​​.控制器应该能够从客户端接收任意数量的字段(1 到 n)并仅更新这些字段.

例如,当 id==1 的用户编辑他的 displayName 时,发布到服务器的数据如下所示:

{"id":"1", "displayName":"jim"}

目前,我们在 UserController 中有一个不完整的解决方案,如下所述:

@RequestMapping(value = "/{id}", method = RequestMethod.POST )公共@ResponseBody ResponseEntity<用户>更新(@RequestBody 用户更新用户){dbUser = userRepository.findOne(updateUser.getId());customObjectMerger(updateUser, dbUser);userRepository.saveAndFlush(updateUuser);...}

这里的代码有效,但有一些问题:@RequestBody 创建一个新的 updateUser,填写 id显示名称.CustomObjectMerger 将此 updateUser 与数据库中相应的 dbUser 合并,更新 updateUser 中包含的唯一字段.>

问题是 Spring 使用默认值和其他自动生成的字段值填充 updateUser 中的某些字段,这些字段在合并时会覆盖我们在 dbUser.明确声明它应该忽略这些字段不是一个选项,因为我们希望我们的 update 也能够设置这些字段.

我正在寻找某种方法让 Spring 仅自动将显式发送到 update() 函数的信息合并到 dbUser(无需重置默认/自动字段值)).有什么简单的方法可以做到这一点吗?

更新:我已经考虑过以下选项,它几乎可以满足我的要求,但并不完全.问题是它需要更新数据作为 @RequestParam 并且(AFAIK)不执行 JSON 字符串:

//将现有用户加载到模型中以注入更新函数@ModelAttribute("用户")公共用户 addUser(@RequestParam(required=false) Long id){if (id != null) 返回 userRepository.findOne(id);返回空;}....//使用@MethodAttribute 预填充模板对象的方法声明@RequestMapping(value = "/{id}", method = RequestMethod.POST )公共@ResponseBody ResponseEntity<用户>更新(@ModelAttribute(用户")用户更新用户){....}

我已经考虑重新编写我的 customObjectMerger() 以更合适地使用 JSON,计算并让它只考虑来自 HttpServletRequest 的字段.但即使必须首先使用 customObjectMerger() 当 spring 提供了几乎正是我正在寻找的东西,减去缺少的 JSON 功能时,感觉很糟糕.如果有人知道如何让 Spring 做到这一点,我将不胜感激!

解决方案

我刚刚遇到了同样的问题.我目前的解决方案是这样的.我还没有做太多测试,但经过初步检查,它看起来运行良好.

@Autowired ObjectMapper objectMapper;@Autowired UserRepository userRepository;@RequestMapping(value = "/{id}", method = RequestMethod.POST )公共@ResponseBody ResponseEntity<用户>update(@PathVariable Long id, HttpServletRequest request) 抛出 IOException{用户用户 = userRepository.findOne(id);用户更新用户 = objectMapper.readerForUpdating(user).readValue(request.getReader());userRepository.saveAndFlush(updatedUser);返回新的 ResponseEntity<>(updatedUser, HttpStatus.ACCEPTED);}

ObjectMapper 是一个 org.codehaus.jackson.map.ObjectMapper 类型的 bean.

希望这对某人有所帮助,

遇到了子对象的问题.如果子对象收到要部分更新的属性,它将创建一个新对象,更新该属性并设置它.这会擦除该对象上的所有其他属性.如果我遇到一个干净的解决方案,我会更新.

We are trying to implement a special partial update function in Spring 3.2. We are using Spring for the backend and have a simple Javascript frontend. I've not been able to find a straight-forward solution to our requirements, which is The update() function should take in any number of field:values and update the persistence model accordingly.

We have in-line editing for all of our fields, so that when the user edits a field and confirms, an id and the modified field get passed to the controller as json. The controller should be able to take in any number of fields from the client (1 to n) and update only those fields.

e.g., when a user with id==1 edits his displayName, the data posted to the server looks like this:

{"id":"1", "displayName":"jim"}

Currently, we have an incomplete solution in the UserController as outlined below:

@RequestMapping(value = "/{id}", method = RequestMethod.POST )
public @ResponseBody ResponseEntity<User> update(@RequestBody User updateUser) {
    dbUser = userRepository.findOne(updateUser.getId());
    customObjectMerger(updateUser, dbUser);
    userRepository.saveAndFlush(updateUuser);
    ...
}

The code here works, but has some issues: The @RequestBody creates a new updateUser, fills in the id and the displayName. CustomObjectMerger merges this updateUser with the corresponding dbUser from the database, updating the only fields included in updateUser.

The problem is that Spring populates some fields in updateUser with default values and other auto-generated field values, which, upon merging, overwrites valid data that we have in dbUser. Explicitly declaring that it should ignore these fields is not an option, as we want our update to be able to set these fields as well.

I am looking into some way to have Spring automatically merge ONLY the information explicitly sent into the update() function into the dbUser (without resetting default/auto field values). Is there any simple way to do this?

Update: I've already considered the following option which does almost what I'm asking for, but not quite. The problem is that it takes update data in as @RequestParam and (AFAIK) doesn't do JSON strings:

//load the existing user into the model for injecting into the update function
@ModelAttribute("user")
public User addUser(@RequestParam(required=false) Long id){
    if (id != null) return userRepository.findOne(id);
    return null;
}
....
//method declaration for using @MethodAttribute to pre-populate the template object
@RequestMapping(value = "/{id}", method = RequestMethod.POST )
public @ResponseBody ResponseEntity<User> update(@ModelAttribute("user") User updateUser){
....
}

I've considered re-writing my customObjectMerger() to work more appropriately with JSON, counting and having it take into consideration only the fields coming in from HttpServletRequest. but even having to use a customObjectMerger() in the first place feels hacky when spring provides almost exactly what I am looking, minus the lacking JSON functionality. If anyone knows of how to get Spring to do this, I'd greatly appreciate it!

解决方案

I've just run into this same problem. My current solution looks like this. I haven't done much testing yet, but upon initial inspection it looks to be working fairly well.

@Autowired ObjectMapper objectMapper;
@Autowired UserRepository userRepository;

@RequestMapping(value = "/{id}", method = RequestMethod.POST )
public @ResponseBody ResponseEntity<User> update(@PathVariable Long id, HttpServletRequest request) throws IOException
{
    User user = userRepository.findOne(id);
    User updatedUser = objectMapper.readerForUpdating(user).readValue(request.getReader());
    userRepository.saveAndFlush(updatedUser);
    return new ResponseEntity<>(updatedUser, HttpStatus.ACCEPTED);
}

The ObjectMapper is a bean of type org.codehaus.jackson.map.ObjectMapper.

Hope this helps someone,

Edit:

Have run into issues with child objects. If a child object receives a property to partially update it will create a fresh object, update that property, and set it. This erases all the other properties on that object. I'll update if I come across a clean solution.

这篇关于Spring 部分更新对象数据绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆