Spring - POST后重定向(即使有验证错误)

时间:2010-03-30 08:35:06

标签: java spring google-app-engine spring-mvc validation

我正在试图找出如何“保留”BindingResult,以便可以通过Spring <form:errors>标记在后续GET中使用它。我想这样做的原因是因为Google App Engine的SSL限制。我有一个通过HTTP显示的表单,帖子是一个HTTPS URL。如果我只转发而不是重定向,那么用户会看到https://whatever.appspot.com/my/form网址。我试图避免这种情况。任何想法如何处理这个?

以下是我想要做的事情,但是当我使用return "create"时,我只会看到验证错误。

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

7 个答案:

答案 0 :(得分:68)

从Spring 3.1开始,您可以使用RedirectAttributes。在执行重定向之前添加要提供的属性。添加BindingResult和您用于验证的对象,在本例中为Register。

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

对于您用于验证的对象,您将使用ModelAttribute的名称。

要使用RedirectAttributes,您必须在配置文件中添加它。您告诉Spring使用一些较新的类:

<mvc:annotation-driven />

现在,无论您何时重定向,都会显示错误

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

答案 1 :(得分:54)

除了奥斯卡的好答案之外,如果您遵循RedirectAttributes方法,请不要忘记您实际上已将modelAttribute传递到重定向的页面。这意味着如果为重定向页面(在控制器中)创建该modelAttribute的新实例,将丢失验证错误。因此,如果您的 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";
}

然后您可能需要在注册创建页面 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/

答案 2 :(得分:1)

问题是您是重定向到新控制器,而不是渲染视图并返回已处理的表单页面。你需要做一些事情:

String FORM_VIEW = wherever_your_form_page_resides

...

if (binding.hasErrors())
    return FORM_VIEW;

由于代码重复字符串,我会将路径保留在任何方法之外。

答案 3 :(得分:1)

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

另一种“不太好”的方法是只使用javascript更改浏览器URL

答案 4 :(得分:1)

我会问你为什么需要重定向。为什么不提交到相同的URL并让它以不同的方式响应POST?不过,如果你真的想这样做:

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

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:-1)

也许这有点过分了,但您是否尝试将其添加到模型中?即,在方法的参数中包含Model,然后将BindingResult添加到它,然后在视图中可用。

model.addAttribute("binding",binding);

我认为你可能不得不使用前向而不是重定向(在我脑海中,我不记得重定向是否会丢失会话 - 我可能错了,因为我没有任何文档方便,即,如果你在将BindingResult添加到模型后没有得到BindingResult,请尝试使用forward来确认这一点。