【问题标题】:Spring MVC 3.0: How do I bind to a persistent objectSpring MVC 3.0:如何绑定到持久对象
【发布时间】:2011-04-09 23:35:18
【问题描述】:
我正在使用 Spring MVC,我希望它从数据库中绑定一个持久对象,但我无法弄清楚如何设置我的代码以在绑定之前调用数据库。例如,我正在尝试将“BenefitType”对象更新到数据库,但是,我希望它从数据库中获取对象,而不是创建新对象,因此我不必更新所有字段。
@RequestMapping("/save")
public String save(@ModelAttribute("item") BenefitType benefitType, BindingResult result)
{
...check for errors
...save, etc.
}
【问题讨论】:
标签:
spring
data-binding
spring-mvc
persistence
spring-3
【解决方案1】:
虽然您的域模型可能非常简单,以至于您可以将 UI 对象直接绑定到数据模型对象,但很可能并非如此,在这种情况下,我强烈建议您为表单设计一个专门的类绑定,然后在它和控制器中的域对象之间进行转换。
【解决方案2】:
我有点困惑。我认为您实际上是在谈论更新工作流程?
你需要两个@RequestMappings,一个用于GET,一个用于POST:
@RequestMapping(value="/update/{id}", method=RequestMethod.GET)
public String getSave(ModelMap model, @PathVariable Long id)
{
model.putAttribute("item", benefitDao.findById(id));
return "view";
}
然后在 POST 上实际更新字段。
在上面的示例中,您的 @ModelAttribute 应该已经填充了类似上述方法的方法,并且使用 JSTL 或 Spring tabglibs 之类的东西与表单支持对象一起绑定属性。
您可能还想查看InitBinder,具体取决于您的用例。
【解决方案3】:
有几种选择:
在最简单的情况下,当您的对象只有简单属性时,您可以将其所有属性绑定到表单字段(hidden,如果需要),并在提交后获得完全绑定的对象。复杂属性也可以使用PropertyEditors 绑定到表单字段。
-
您也可以使用会话在GET 和POST 请求之间存储您的对象。 Spring 3 通过@SessionAttributes 注释(来自Petclinic sample)促进了这种方法:
@Controller
@RequestMapping("/owners/*/pets/{petId}/edit")
@SessionAttributes("pet") // Specify attributes to be stored in the session
public class EditPetForm {
...
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
// Disallow binding of sensitive fields - user can't override
// values from the session
dataBinder.setDisallowedFields("id");
}
@RequestMapping(method = RequestMethod.GET)
public String setupForm(@PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet); // Put attribute into session
return "pets/form";
}
@RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(@ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
} else {
this.clinic.storePet(pet);
// Clean the session attribute after successful submit
status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId();
}
}
}
但是,如果表单的多个实例在同一个会话中同时打开,这种方法可能会导致问题。
因此,对于复杂情况,最可靠的方法是创建一个单独的对象来存储表单字段,并手动将来自该对象的更改合并到持久对象中。
【解决方案4】:
所以我最终通过在类中使用同名的@ModelAttribute 注释方法来解决这个问题。 Spring 在执行请求映射之前先构建模型:
@ModelAttribute("item")
BenefitType getBenefitType(@RequestParam("id") String id) {
// return benefit type
}