7.5.2 使用 flash 属性

假设我们不想在重定向中发送 username 或 ID 了,而是要发送实际的 Spitter 对象。如果我们只发送 ID 的话,那么处理重定向的方法还需要从数据库中查找才能得到 Spitter 对象。但是,在重定向之前,我们其实已经得到了 Spitter 对象。为什么不将其发送给处理重定向的方法,并将其展现出来呢?

Spitter 对象要比 String 和 int 更为复杂。因此,我们不能像路径变量或查询参数那么容易地发送 Spitter 对象。它只能设置为模型中的属性。

但是,正如我们前面所讨论的那样,模型数据最终是以请求参数的形式复制到请求中的,当重定向发生的时候,这些数据就会丢失。因此,我们需要将 Spitter 对象放到一个位置,使其能够在重定向的过程中存活下来。

有个方案是将 Spitter 放到会话中。会话能够长期存在,并且能够跨多个请求。所以我们可以在重定向发生之前将 Spitter 放到会话中,并在重定向后,从会话中将其取出。当然,我们还要负责在重定向后在会话中将其清理掉。

实际上,Spring 也认为将跨重定向存活的数据放到会话中是一个很不错的方式。但是,Spring 认为我们并不需要管理这些数据,相反,Spring 提供了将数据发送为 flash 属性(flash attribute)的功能。 按照定义,flash 属性会一直携带这些数据直到下一次请求,然后才会消失。

Spring 提供了通过 RedirectAttributes 设置 flash 属性的方法,这是 Spring 3.1 引入的 Model 的一个子接口。RedirectAttributes 提供了 Model 的所有功能,除此之外,还有几个方法是用来设置 flash 属性的。 具体来讲,Redirect-Attributes 提供了一组 addFlashAttribute() 方法来添加 flash 属性。重新看一 下 processRegistration() 方法,我们可以使用 addFlashAttribute() 将 Spitter 对象添加到模型中:

@RequestMapping(value="/register", method=POST)
public String processRegistration(
    Spitter spitter, RedirectAttribute model) {
  spitterRespository.save(spitter);
  model.addAttribute("username", spitter.getUsername());
  model.addFlashAttribute("spitter", spitter);
  return "redirect:/spitter/{username}";
}

在这里,我们调用了 addFlashAttribute() 方法,并将 spitter 作为 key,Spitter 对象作为值。另外,我们还可以不设置 key 参数,让 key 根据值的类型自行推断得出:

model.addFlashAttribute(spitter);

因为我们传递了一个 Spitter 对象给 addFlashAttribute() 方法,所以推断得到的 key 将会是 spitter。

在重定向执行之前,所有的 flash 属性都会复制到会话中。在重定向后,存在会话中的 flash 属性会被取出,并从会话转移到模型之中。处理重定向的方法就能从模型中访问 Spitter 对象了,就像获取其他的模型对象一样。图 7.2 阐述了它是如何运行的。

为了完成 flash 属性的流程,如下展现了更新版本的 showSpitterProfile() 方法,在从数据库中查找之前,它会首先从模型中检查 Spitter 对象:

@RequestMapping(value="/{username}", method=GET)
public String showSpitterProfile(
    @PathVariable String username, Model model) {
  if (!model.containsAttribute("spitter")) {
    model.addAttribute(spitterRepository.findByUsername(username));
  }
  return "profile";
}

可以看到,showSpitterProfile() 方法所做的第一件事就是检查是否存有 key 为 spitter 的 model 属性。如果模型中包含 spitter 属性,那就什么都不用做了。这里面包含的 Spitter 对象将会传递到视图中进行渲染。但是如果模型中不包含 spitter 属性的话,那么 showSpitterProfile() 将会从 Repository 中查找 Spitter,并将其存放到模型中。

Last updated