【问题标题】:Preserving model state with Post/Redirect/Get pattern and URL rewriting使用 Post/Redirect/Get 模式和 URL 重写保留模型状态
【发布时间】:2016-01-19 16:50:59
【问题描述】:

首先,我知道关于“使用 Post/Redirect/Get 模式保留模型状态”有类似的问题,但这些都没有我非常具体的问题:

背景

我的代码在企业 CMS 软件中运行,该软件可以做很多事情。其中之一是 URL 重写:每当我生成指向控制器的链接时,取决于环境,链接会缩短 - 这是 SEO 的事情,无法讨论。

即如果我的控制器 URL 是 /webapp/servlet/myController/doSomething,则生成的 URL 将是 /myController/doSomething。我们必须使用一些 LinkProcessing 功能。

当apache使用mod_rewrite调用tomcat上的对应代码时,apache重写规则会将这个短url扩展为/webapp/servlet/myController/doSomething

RewriteCond %{REQUEST_URI} ^/myController/(.*)
RewriteRule ^/myController/(.*) /webapp/servlet/myController/$1 [PT,L]

问题

我正在尝试使用 Spring 3.1.2 实现 Post/Redirect/Get 模式。我正在生成一个表单并将其发布到控制器,控制器使用 GET 验证并重定向到成功或错误页面(Post/Redirect/Get 模式)。

(高度简化)代码

@RequestMapping()
public class MyController {

  @RequestMapping(value = "/doDispatch", method = RequestMethod.POST)
  public RedirectView handleDispatch(RedirectAttributes redirectAttributes,
                                     @Validated @ModelAttribute FormBean formBean,
                                     BindingResult binding) {
    if (binding.hasErrors()) {
      redirectAttributes.addFlashAttribute(formBean);
      redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"formBean", binding);

      return new RedirectView(generateLink("/error"));
    } else {
      redirectAttributes.addFlashAttribute(formBean);
      redirectAttributes.addFlashAttribute(BindingResult.MODEL_KEY_PREFIX+"formBean", binding);
      return new RedirectView(generateLink("/success"));

    }
  }

  @RequestMapping(value = "/success")
  public ModelAndView handleSuccess(@ModelAttribute FormBean formBean) {
    // do stuff (save things in the DB)
    // ...

    final ModelAndView modelAndView = createModelAndView(formBean);
    modelAndView.addObject("success", true);
    return modelAndView;
  }
  @RequestMapping(value = "/error")
  public ModelAndView handleError(@Validated @ModelAttribute FormBean formBean,
                                  BindingResult binding) {
    final ModelAndView modelAndView = createModelAndView(formBean);
    modelAndView.addObject("binding", binding);
    modelAndView.addObject("formBean", formBean);
    return modelAndView;
  }
}

问题在于此 generateLink() 方法将生成以/webapp/servlet 开头的链接或不生成链接 - 取决于环境/成功。这就是整个 Enterprice CMS 的运作方式。 (这是不能讨论的​​部分)

另一方面,Spring Flash-Attributes 与返回的 URL 协同工作,并将 URL 存储为 FlashMap 的一部分:

引用http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-flash-attributes

为减少出现此类问题的可能性,RedirectView 自动使用目标重定向 URL 的路径和查询参数“标记”FlashMap 实例。反过来,在查找“输入”FlashMap 时,默认的 FlashMapManager 会将该信息与传入的请求相匹配。

由于下一个请求(假设我遇到错误并返回“/myController/error”)将扩展为/webapp/servlet/myController/error,因此 FlashMap 将不适用于此请求,因为 URL 不匹配

负责的代码是这里(AbstractFlashMapManager.java:157ff):

  protected boolean isFlashMapForRequest(FlashMap flashMap, HttpServletRequest request) {

    if (flashMap.getTargetRequestPath() != null) {
      String requestUri = this.urlPathHelper.getOriginatingRequestUri(request);
      if (!requestUri.equals(flashMap.getTargetRequestPath())
          && !requestUri.equals(flashMap.getTargetRequestPath() + "/")) {
        return false;
      }
    }
    // ...
  }

问题

您知道一方面我仍然可以生成短 URL,但将 FlashAttributes 传递给以下 GET 请求的方法吗?

最好的问候和提前感谢您的帮助, 亚历山大

【问题讨论】:

    标签: java spring spring-mvc mod-rewrite post-redirect-get


    【解决方案1】:

    到目前为止,我发现的最佳解决方案是使用 Interceptor 更新 targetRequestPath,方法是将 /<webappPath>/<servletPath> 前缀为来自 RequestContextUtils.getOutputFlashMap(request) 的那些缺少此信息的 FlashMap。 顺便说一句:这只能在afterCompletion 方法中完成,否则在使用RedirectView 时根本不会设置targetRequestPath

    还有其他更好的解决方案吗?

    【讨论】:

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