使用Post/Redirect/Get模式保存模型状态

8

目前,我正在尝试在Spring MVC 3.1中实现Post/Redirect/Get模式。如何正确地保留和恢复模型数据和验证错误?我知道可以使用RedirectAttributes在POST方法中保存模型和BindingResult。但是,从flash范围中的GET方法中恢复它们的正确方式是什么?

我已经完成了以下POST操作:

    @RequestMapping(value = "/user/create", method = RequestMethod.POST)
public String doCreate(@ModelAttribute("user") @Valid User user, BindingResult result, RedirectAttributes rA){

    if(result.hasErrors()){
        rA.addFlashAttribute("result", result);
        rA.addFlashAttribute("user", user);

        return "redirect:/user";
    }

    return "redirect:/user/success";
}

以下是获取用户创建表单的GET请求:

    @RequestMapping(value = "/user", method = RequestMethod.GET)
public ModelAndView showUserForm(@ModelAttribute("user") User user, ModelAndView model){

    model.addObject("user", user);
    model.setViewName("userForm");

    return model;
}

这样可以在出现错误时保存给定的用户数据。但是恢复错误的正确方式是什么?(BindingResult)我想用Spring表单标签在表单中显示它们:

<form:errors path="*" />

此外,如何从get方法访问Flash范围也是一个有趣的问题?
3个回答

3
public class BindingHandlerInterceptor extends HandlerInterceptorAdapter {

    public static final String BINDING_RESULT_FLUSH_ATTRIBUTE_KEY = BindingHandlerInterceptor.class.getName() + ".flashBindingResult";

    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {


        if(METHOD_POST.equals(request.getMethod())) {

            BindingResult bindingResult = getBindingResult(modelAndView);

            FlashMap outFlash = RequestContextUtils.getOutputFlashMap(request);

            if(bindingResult == null || ! bindingResult.hasErrors() || outFlash == null ) {
                return;
            }

            outFlash.put(BINDING_RESULT_FLUSH_ATTRIBUTE_KEY, bindingResult);

        }

        Map<String, ?> inFlash = RequestContextUtils.getInputFlashMap(request);

        if(METHOD_GET.equals(request.getMethod()) && inFlash != null && inFlash.containsKey(BINDING_RESULT_FLUSH_ATTRIBUTE_KEY)) {

            BindingResult flashBindingResult = (BindingResult)inFlash.get(BINDING_RESULT_FLUSH_ATTRIBUTE_KEY);

            if(flashBindingResult != null) {

                BindingResult bindingResult = getBindingResult(modelAndView);

                if(bindingResult == null) {
                    return;
                }

                bindingResult.addAllErrors(flashBindingResult);

            }

        }

    }

    public static BindingResult getBindingResult(ModelAndView modelAndView) {

        if(modelAndView == null) {
            return null;
        }

        for (Entry<String,?> key : modelAndView.getModel().entrySet()) {
            if(key.getKey().startsWith(BindingResult.MODEL_KEY_PREFIX)) {
                return (BindingResult)key.getValue();
            }
        }

        return null;
    }


}

1
为什么绑定失败后不显示更新表单,以便用户可以尝试重新提交表单呢?
标准方法似乎是从POST处理程序方法返回更新表单视图。
if (bindingResult.hasErrors()) {
  uiModel.addAttribute("user", user);
  return "user/create";
}

您可以使用form:errors标签来显示错误信息。

5
这忽略了问题的核心。他试图避免在POST中返回屏幕,因为浏览器处理已发布的表单时可能会出现问题。如果用户点击刷新或返回,表单将被重新提交,这可能导致服务器上的状态修改两次。最好使用get方法将它们重定向回原始表单。 - chubbsondubs

0
“从flash范围中的GET方法恢复它们的正确方式是什么?”
“我不确定您所说的恢复是什么意思。在重定向之前添加的flash属性将在重定向后成为模型的一部分。没有任何特殊的操作需要执行。我猜您想问其他问题,但我不确定是什么。”
“正如phahn指出的那样,为什么要在错误时重定向?处理这种情况的常见方法是在成功时进行重定向。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接