春季 – POST后redirect(即使有validation错误)

我想弄清楚如何“保留”BindingResult,以便通过Spring <form:errors>标签在后续的GET中使用它。 我想这样做的原因是由于Google App Engine的SSL限制。 我有一个通过HTTP显示的表单,并且这个表单是一个HTTPS URL。 如果我只转发而不是redirect,那么用户会看到https://whatever.appspot.com/my/formurl。 我试图避免这一点。 任何想法如何处理这个?

下面是我想要做的,但是当我使用return "create"时候,我只看到validation错误。

 @RequestMapping(value = "/submit", method = RequestMethod.POST) public final String submit( @ModelAttribute("register") @Valid final Register register, final BindingResult binding) { if (binding.hasErrors()) { return "redirect:/register/create"; } return "redirect:/register/success"; } 

自Spring 3.1以来,您可以使用RedirectAttributes。 在redirect之前添加您想要的可用属性。 添加BindingResult和你用来validation的对象,在这种情况下,注册。

对于BindingResult,您将使用名称:“org.springframework.validation.BindingResult。[ModelAttribute的名称]”。

对于您用来validation的对象,您将使用ModelAttribute的名称。

要使用RedirectAttributes,你必须在configuration文件中添加这个。 除此之外,你正在告诉Spring使用一些更新的类:

 <mvc:annotation-driven /> 

现在,错误将显示在任何你redirect

 @RequestMapping(value = "/submit", method = RequestMethod.POST) public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) { if (binding.hasErrors()) { attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding); attr.addFlashAttribute("register", register); return "redirect:/register/create"; } return "redirect:/register/success"; } 

除了奥斯卡好的答案之外,如果您遵循RedirectAttributes方法,请不要忘记您实际上是将modelAttribute传递给redirect的页面。 这意味着如果您为redirect的页面(在控制器中)创build该modelAttribute的新实例, 则将失去validation错误 。 所以,如果你的POST控制器方法是这样的:

 @RequestMapping(value = "/submit", method = RequestMethod.POST) public final String submit(@ModelAttribute("register") @Valid final Register register, final BindingResult binding, RedirectAttributes attr, HttpSession session) { if (binding.hasErrors()) { attr.addFlashAttribute("org.springframework.validation.BindingResult.register", binding); attr.addFlashAttribute("register", register); return "redirect:/register/create"; } return "redirect:/register/success"; } 

那么你可能需要在你的注册创build页面GET控制器中进行修改。 由此:

 @RequestMapping(value = "/register/create", method = RequestMethod.GET) public String registerCreatePage(Model model) { // some stuff model.addAttribute("register", new Register()); // some more stuff } 

 @RequestMapping(value = "/register/create", method = RequestMethod.GET) public String registerCreatePage(Model model) { // some stuff if (!model.containsAttribute("register")) { model.addAttribute("register", new Register()); } // some more stuff } 

来源: http : //gerrydevstory.com/2013/07/11/preserving-validation-error-messages-on-spring-mvc-form-post-redirect-get/

问题是你redirect到一个新的控制器,而不是呈现视图,并返回处理的表单页面。 你需要做一些事情:

 String FORM_VIEW = wherever_your_form_page_resides ... if (binding.hasErrors()) return FORM_VIEW; 

由于string的代码重复,我会保留任何方法以外的path。

在请求之间保持对象的唯一方法(即redirect)是将对象存储在会话属性中。 所以你可以在两个方法(即get和post)的方法参数中包含“HttpServletRequest请求”,并通过request.getAttribute(“binding”)检索对象。 这就是说,并没有尝试过自己,你可能需要弄清楚如何重新绑定绑定到新的请求中的对象。

另一个“更好的”方法是使用JavaScript更改浏览器的URL

我会质疑为什么你需要redirect。 为什么不只是提交到相同的url,并有不同的反应,以邮政? 不过,如果你真的想这样做:

 @RequestMapping(value = "/submit", method = RequestMethod.POST) public final String submit( @ModelAttribute("register") @Valid final Register register, final BindingResult binding, HttpSession session) { if (binding.hasErrors()) { session.setAttribute("register",register); session.setAttribute("binding",binding); return "redirect:/register/create"; } return "redirect:/register/success"; } 

然后在你的“创build”方法中:

 model.put("register",session.getAttribute("register")); model.put("org.springframework.validation.BindingResult.register",session.getAttribute("register")); 

我不知道Google App Engine的具体问题,但使用ForwardedHeaderFilter可能有助于保留客户端使用的原始scheme。 这个filter是在Spring Framework 4.3中添加的,但是一些Servlet容器提供了类似的filter,filter是自给自足的,所以你也可以在需要的时候抓取源代码。

也许这有点简单,但你有没有尝试将它添加到你的模型? 也就是说,将模型包含在方法的参数中,然后将BindingResult添加到它,然后在您的视图中可用。

 model.addAttribute("binding",binding); 

我想你可能不得不使用前进而不是redirect(在我的脑海中,我不记得redirect是否会丢失会话 – 我可能是错误的,因为我没有任何文档方便,即如果你添加到模型后没有得到BindingResult,试着使用forward来确认)。