【问题标题】:Preserving model state with Post/Redirect/Get pattern使用 Post/Redirect/Get 模式保留模型状态
【发布时间】:2012-02-17 14:12:22
【问题描述】:

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

我对 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";
}

以及以下获取用户创建表单:

    @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 范围会很有趣?

【问题讨论】:

    标签: forms spring-mvc


    【解决方案1】:
    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;
        }
    
    
    }
    

    【讨论】:

      【解决方案2】:

      为什么绑定失败后不显示更新表单,让用户可以尝试重新提交表单?

      对此的标准方法似乎是从 POST 处理程序方法返回更新表单视图。

      if (bindingResult.hasErrors()) {
        uiModel.addAttribute("user", user);
        return "user/create";
      }
      

      然后您可以使用 form:errors 标签显示错误。

      【讨论】:

      • 这忽略了问题的全部要点。由于浏览器如何处理已发布的表单,他试图避免在 POST 中返回屏幕。如果用户点击刷新或返回,表单会被重新发布,这可能会导致服务器上的状态被修改两次。使用 get 将它们重定向回原始表单要好得多。
      【解决方案3】:

      在 GET 方法中从 闪光范围

      我不确定我是否理解你所说的恢复它们的意思。在重定向之前添加为 flash 属性的内容将在重定向之后的模型中。没有什么特别需要做的。我猜你想问别的问题,但我不确定那是什么。

      正如 phahn 指出的那样,您为什么会在错误时重定向?处理此问题的常用方法是在成功时重定向。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-21
        • 2017-09-04
        • 1970-01-01
        • 2016-08-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多