SpringMVC controller: how to stay on page if form validation error occurs

匿名 (未验证) 提交于 2019-12-03 01:59:02

问题:

I have next working code in my SpringMVC controller:

@RequestMapping(value = "/register", method = RequestMethod.GET) public void registerForm(Model model) {     model.addAttribute("registerInfo", new UserRegistrationForm()); }  @RequestMapping(value = "/reg", method = RequestMethod.POST) public String create(         @Valid @ModelAttribute("registerInfo") UserRegistrationForm userRegistrationForm,         BindingResult result) {      if (result.hasErrors()) {         return "register";     }     userService.addUser(userRegistrationForm);     return "redirect:/"; } 

In short create method try to validate UserRegistrationForm. If form has errors, it leaves user on the same page with filled form fields where error message will be shown.

Now I need to apply the same behaviour to another page, but here I have a problem:

@RequestMapping(value = "/buy/{buyId}", method = RequestMethod.GET) public String buyGet(HttpServletRequest request, Model model, @PathVariable long buyId) {     model.addAttribute("buyForm", new BuyForm());     return "/buy"; }  @RequestMapping(value = "/buy/{buyId}", method = RequestMethod.POST) public String buyPost(@PathVariable long buyId,                           @Valid @ModelAttribute("buyForm") BuyForm buyForm,                           BindingResult result) {      if (result.hasErrors()) {         return "/buy/" + buyId;     }      buyForm.setId(buyId);     buyService.buy(buyForm);     return "redirect:/show/" + buyId; } 

I faced with issue of dynamic url. Now if form has errors I should specify the same page template to stay on current page, but also I should pass buyId as a path variable. Where are a conflict in this two requirements. If I leave this code as is, I get an error (I'm using Thymeleaf as a template processor):

Error resolving template "/buy/3", template might not exist or might not be accessible by any of the configured Template Resolvers 

I can write something like return "redirect:/buy/" + buyId, but in this case I lose all data and errors of form object.

What should I do to implement in buyPost method the same behaviour as in create method?

回答1:

I tried the solution metioned in this post at this weekend, but it doesn't work for BindingResult.

The code below works but not perfect.

@ModelAttribute("command") public PlaceOrderCommand command() {     return new PlaceOrderCommand(); }  @RequestMapping(value = "/placeOrder", method = RequestMethod.GET) public String placeOrder(         @ModelAttribute("command") PlaceOrderCommand command,         ModelMap modelMap) {     modelMap.put(BindingResult.MODEL_KEY_PREFIX + "command",             modelMap.get("errors"));     return "placeOrder"; }  @RequestMapping(value = "/placeOrder", method = RequestMethod.POST) public String placeOrder(         @Valid @ModelAttribute("command") PlaceOrderCommand command,         final BindingResult bindingResult, Model model,         final RedirectAttributes redirectAttributes) {     if (bindingResult.hasErrors()) {         redirectAttributes.addFlashAttribute("errors", bindingResult);          //it doesn't work when passing this                   //redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX + "command", bindingResult);          redirectAttributes.addFlashAttribute("command", command);         return "redirect:/booking/placeOrder";     }     ...... } 


回答2:

*I'm using Hibernate Validator APIs to validate my beans. To preserve form data along with displaying error messages, you need to do these 3 things:

  1. Annotate your bean (eg. @NotEmpty, @Pattern, @Length, @Email etc.)

  1. Inside controller:

    @Controller public class RegistrationController {

    @Autowired private RegistrationService registrationService;  @RequestMapping(value="register.htm", method=RequestMethod.GET, params="new") public String showRegistrationForm(Model model) {     if (!model.containsAttribute("employee")) {         model.addAttribute("employee", new Employee());     }     return "form/registration"; }  @RequestMapping(value="register.htm", method=RequestMethod.POST) public String register(@Valid @ModelAttribute("employee") Employee employee, BindingResult bindingResult, RedirectAttributes redirectAttributes) {     if (bindingResult.hasErrors()) {         redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.employee", bindingResult);         redirectAttributes.addFlashAttribute("employee", employee);         return "redirect:register.htm?new";     }     registrationService.save(employee);     return "workspace"; } // .... 

    }

  2. Update your view/jsp to hold error messages:

This article can surely be helpful.



回答3:

You can change your POST implementation to this:

@RequestMapping(value = "/buy/{buyId}", method = RequestMethod.POST) public String buyPost(@PathVariable long buyId,                           @Valid @ModelAttribute("buyForm") BuyForm buyForm,                           BindingResult result) {      buyForm.setId(buyId); // important to do this also in the error case, otherwise,                            // if the validation fails multiple times it will not work.      if (result.hasErrors()) {         byForm.setId(buyId);         return "/buy/{buyId}";     }      buyService.buy(buyForm);     return "redirect:/show/{buyId}"; } 

Optionally, you can also annotate the method with @PostMapping("/buy/{buyId}") if you use Spring 4.3 or higher.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!