当只显示Spring MVC模型bean的一部分时,有没有办法只在模型中更新从浏览器返回的内容?
假设我们有一个User类(当然这只是公共属性):
public class User {
public String firstName;
public String lastName;
public String email;
public Date subscriptionExpiration;
}
现在我将前三个属性显示为JSP中的输入字段,并希望相应地更新数据库中的对象。只应更新这3个参数,而不是第4个参数。实现这一目标的一种方法是
@RequestMapping("/user/{userId}", method=RequestMethod.POST)
public String saveChanges(@PathVariable userId, User user, Model model) {
User oldUser = User.loadFromDB(userId);
oldUser.firstName = user.firstName;
oldUser.lastName = user.lastName;
oldUser.email = user.email;
oldUser.saveToDB();
model.addAttribute("user", oldUser);
}
但这意味着硬编码所有可能改变的属性,我不太喜欢。
有没有办法根据用户允许更改的内容确定要更新的字段?该机制应该比仅假设请求参数中的所有内容都可以更改更聪明,否则任何精明的用户都可以手动将其他字段注入请求中。
使用@Entity(dynamicUpdate = true)并不能解决我眼中的问题,因为我没有在请求中获得整个User对象,这样做会打开很多安全漏洞。
我在Spring中错过了一个不错的功能,还是有其他方法可以从概念上解决这个问题?任何提示都非常感谢!
答案 0 :(得分:3)
请参阅this question以了解如何使用@InitBinder来允许/阻止某些模型字段被Spring绑定以请求参数。这样可以确保通过注入请求参数来确保无法修改subscriptionExpiration
。
请参阅the documentation了解如何在方法和方法参数上使用@ModelAttribute注释从数据库加载用户并在调用@RequestMapping方法之前将其添加到模型中,并填充此用户调用@RequestMapping方法时使用请求参数。这允许从DB获取用户并让Spring使用来自请求的ne值填充它。您所要做的就是验证用户的新状态并将其保存到数据库中。
答案 1 :(得分:2)
我认为方法
BeanUtils.copyProperties(Object source, Object target, String[] ignoreProperties)
做你想要的。它将所有属性从一个对象复制到另一个对象,而不触及String[] ignoreProperties
中定义的属性。
将给定源bean的属性值复制到给定的目标bean中,忽略给定的“ignoreProperties”。
注意:只要属性匹配,源类和目标类就不必相互匹配,甚至不必相互派生。
表示源bean暴露但目标bean不会被忽略的任何bean属性。这只是一种方便的方法。对于更复杂的传输需求,请考虑使用完整的BeanWrapper。
答案 2 :(得分:0)
您可以先从数据库中读取对象,然后绑定请求。您可以在FuWeSta-Sample找到一个示例。
它使用helper-bean,必须由Spring初始化。
答案 3 :(得分:0)
一个选项是使用表单中的隐藏字段。一个带退回的选项,但它适用于某些情况
答案 4 :(得分:0)
您正在寻找的好功能是@ModelAttribute。我假设您的表单也会发布用户ID。
public class UserController {
@ModelAttribute
public User getUser(@RequestParam(value = "id", required = false) Long id) {
return User.loadFromDB(id);
}
@RequestMapping("/user/{id}", method=RequestMethod.POST)
public String saveChanges(@ModelAttribute User user, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
// return ...
}
// model.asMap().clear();
user.saveToDB();
// return ...
}
}
答案 5 :(得分:0)
我有同样的问题,最后只需添加类型转换器即可解决。
public class AbstractDocumentConverter implements Converter<String, AbstractDocument> {
private AbstractDocumentRepository abstractDocumentRepository;
public AbstractDocumentConverter(AbstractDocumentRepository abstractDocumentRepository) {
this.abstractDocumentRepository = abstractDocumentRepository;
}
@Override
public AbstractDocument convert(String id) {
return abstractDocumentRepository.findOne(id);
}
}
我使用mongodb,AbstractDocument是我所有文档的超类,在控制器中添加@ModelAttribute(“ id”)。
@RequestMapping("save")
public String save(@ModelAttribute("id") SportGame game) {
sportGameService.save(game);
return "redirect:/game/list";
}
它将首先将id转换为模型(在我的转换器中,它是通过id从db中找到一个),然后从请求参数中填充模型字段。