使用Post / Redirect / Get模式和URL重写保留模型状态

时间:2016-01-19 16:50:59

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

首先,我知道有关于"使用Post / Redirect / Get模式"保留模型状态的类似问题,但这些都没有我特定的问题:

背景

我的代码正在使用企业CMS软件,它可以完成很多工作。其中一个是URL重写:每当我生成链接到我的控制器,依赖于环境,链接都会缩短 - 这是一个SEO的东西,不能讨论。

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

当apache使用/webapp/servlet/myController/doSomething来调用tomcat上的相应代码时,apache重写规则会将此短网址扩展为mod_rewrite

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

问题

我尝试使用Spring 3.1.2实现Post / Redirect / Get模式。我正在生成一个表单并将其POST到Controller,后者使用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会自动"盖章" FlashMap个实例,包含目标重定向URL的路径和查询参数。反过来,当查找"输入时,默认FlashMapManager会将该信息与传入请求进行匹配。 FlashMap

由于下一个请求(让我们说我有错误并返回" / myController /错误")将扩展为/webapp/servlet/myController/error,FlashMap将不会适用于此请求,因为网址不匹配

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

  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;
      }
    }
    // ...
  }

问题

您是否知道我如何仍然可以生成短网址,但是将FlashAttributes传递给以下GET请求?

致以最诚挚的问候和感谢您的帮助, 亚历山大

1 个答案:

答案 0 :(得分:0)

我到目前为止找到的最佳解决方案是使用Interceptor更新targetRequestPath,为/<webappPath>/<servletPath>添加RequestContextUtils.getOutputFlashMap(request)前缀afterCompletion的那些缺少此内容的FlashMaps信息。 BTW :这只能在targetRequestPath方法中完成,因为否则在使用RedirectView时根本不会设置$scope

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