SpringMVC控制器:如果发生表单验证错误,如何保持在页面上

时间:2013-08-08 22:33:28

标签: validation spring-mvc

我的 SpringMVC 控制器中有下一个工作代码:

@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:/";
}

简而言之create方法尝试验证UserRegistrationForm。如果表单有错误,它会将用户留在同一页面上,其中填写的表单字段将显示错误消息。

现在我需要将相同的行为应用到另一个页面,但是我遇到了一个问题:

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

我遇到了动态网址的问题。现在,如果表单有错误,我应该指定相同的页面模板以保留在当前页面上,但我也应该将buyId作为路径变量传递。这两个要求在哪里发生冲突。如果我按原样保留此代码,则会出现错误(我使用 Thymeleaf 作为模板处理器):

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

我可以编写类似return "redirect:/buy/" + buyId的内容,但在这种情况下,我会丢失表单对象的所有数据和错误。

我应该如何在buyPost方法中实现与create方法相同的行为?

3 个答案:

答案 0 :(得分:3)

本周末我尝试了这个post中提到的解决方案,但它对BindingResult不起作用。

以下代码有效但不完美。

@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";
    }
    ......
}

答案 1 :(得分:2)

*我使用Hibernate Validator APIs来验证我的bean。要保留表单数据以及显示错误消息,您需要执行以下三项操作:

  1. 注释你的bean(例如@NotEmpty,@ Pattern,@ Length,@ Email等)
  2. enter image description here

    1. 内部控制器:

      @Controller 公共类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. 更新您的view / jsp以保留错误消息:

    3. enter image description here

      article肯定会有所帮助。

答案 2 :(得分:0)

您可以将POST实施更改为:

@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}";
}

如果您使用的是Spring 4.3或更高版本,也可以使用@PostMapping("/buy/{buyId}")注释该方法。