zoukankan      html  css  js  c++  java
  • 笔记35 跨重定向请求传递数

    在控制器方法返回的视图名称中,我们借助 了“redirect:”前缀的力量。当控制器方法返回的String值 以“redirect:”开头的话,那么这个String不是用来查找视图的, 而是用来指导浏览器进行重定向的路径。

    1 return "redirect:/spitter/" + spitter.getUsername(); 

    一般来讲,当一个处理器方法完成之后,该方法所指定的 模型数据将会复制到请求中,并作为请求中的属性,请求会转发 (forward)到视图上进行渲染。因为控制器方法和视图所处理的是同一个请求,所以在转发的过程中,请求属性能够得以保存。

    但是,如下图所示,当控制器的结果是重定向的话,原始的请求就 结束了,并且会发起一个新的GET请求。原始请求中所带有的模型数 据也就随着请求一起消亡了。在新的请求属性中,没有任何的模型数 据,这个请求必须要自己计算数据。

    显然,对于重定向来说,模型并不能用来传递数据。但是也有一 些其他方案,能够从发起重定向的方法传递数据给处理重定向方法 中:

    • 使用URL模板以路径变量和/或查询参数的形式传递数据;
    • 通过flash属性发送数据。 

     一、通过URL模板进行重定向

    username的值直接连接到重 定向String上的。

    代码如下:

     1     @RequestMapping(value = "/register", method = RequestMethod.POST)
     2     public String processRegistration(@Validated Spitter spitter, BindingResult errors, Model model) {
     3 
     4         SpitterRegisterValidator spitterValidator = new SpitterRegisterValidator();
     5         spitterValidator.validate(spitter, errors);
     6         model.addAttribute("username", spitter.getUsername());
     7         if (errors.hasErrors()) {
     8             return "registerForm3";
     9         } else {
    10             spitterRepository.save(spitter);
    11             // return "redirect:/spitter/" + spitter.getUsername();
    12             return "redirect:/spitter/{username}";
    13         }
    14 
    15     }

    现在,username作为占位符填充到了URL模板中,而不是直接连接 到重定向String中,所以username中所有的不安全字符都会进行 转义。这样会更加安全,这里允许用户输入任何想要的内容作 为username,并会将其附加到路径上。 

    除此之外,模型中所有其他的原始类型值都可以添加到URL中作为查 询参数。作为样例,假设除了username以外,模型中还要包含新创建 Spitter对象的id属性,那processRegistration()方法可以改 写为如下的形式:

     1     @RequestMapping(value = "/register", method = RequestMethod.POST)
     2     public String processRegistration(@Validated Spitter spitter, BindingResult errors, Model model) {
     3 
     4         SpitterRegisterValidator spitterValidator = new SpitterRegisterValidator();
     5         spitterValidator.validate(spitter, errors);
     6         model.addAttribute("username", spitter.getUsername());
     7         model.addAttribute("spitterId", spitter.getId());
     8         if (errors.hasErrors()) {
     9             return "registerForm3";
    10         } else {
    11             spitterRepository.save(spitter);
    12             // return "redirect:/spitter/" + spitter.getUsername();
    13             return "redirect:/spitter/{username}";
    14         }
    15 
    16     }

    所返回的重定向String并没有太大的变化。但是,因为模型中的 spitterId属性没有匹配重定向URL中的任何占位符,所以它会自 动以查询参数的形式附加到重定向URL上。 

    通过路径变量和查询参数的形式跨重定向传递数据是很简单直接的方 式,但它也有一定的限制。它只能用来发送简单的值,如String和 数字的值。在URL中,并没有办法发送更为复杂的值,但这正 是flash属性能够提供帮助的领域。 

    二、使用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属 性的。 RedirectAttributes提供了一组 addFlashAttribute()方法来添加flash属性。

     1 @RequestMapping(value = "/register", method = RequestMethod.POST)
     2     public String processRegistration(@Validated Spitter spitter, BindingResult errors, RedirectAttributes model) {
     3 
     4         SpitterRegisterValidator spitterValidator = new SpitterRegisterValidator();
     5         spitterValidator.validate(spitter, errors);
     6         model.addAttribute("username", spitter.getUsername());
     7         model.addAttribute("spitterId", spitter.getId());
     8         model.addFlashAttribute("spitter", spitter);
     9         if (errors.hasErrors()) {
    10             return "registerForm3";
    11         } else {
    12             spitterRepository.save(spitter);
    13             // return "redirect:/spitter/" + spitter.getUsername();
    14             return "redirect:/spitter/{username}";
    15         }
    16 
    17     }

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

    1  model.addFlashAttribute(spitter);

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

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

    1     @RequestMapping(value = "/{username}", method = RequestMethod.GET)
    2     public String showSpitterProfile(@PathVariable String username, Model model) {
    3         if (!model.containsAttribute("spitter")) {
    4             model.addAttribute(spitterRepository.findByUsername(username));
    5         }
    6         // Spitter spitter = spitterRepository.findByUsername(username);
    7         // model.addAttribute(spitter);
    8         return "profile";
    9     }

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

    注:在保存spitter对象时,即插入数据库时并没有设置Id值,而是对应数据库中一个自增字段Id,所以显示是第0个用户,原来在显示个人信息的时候是通过在数据库中根据用户名查询对应的spitter对象信息,所以会显示注册id。

  • 相关阅读:
    iOS 网络NSURLConnection
    iOS RunLoop
    iOS 多线程及其他补充 02
    iOS 多线程 01
    iOS UI进阶06
    iOS UI进阶05
    ios 调试命令(oc用”po self“,swift用“frame variable self”)
    ios 视频编辑,添加文字、图片(CA动画)水印,合成视频
    ios 添加openssl库
    ios 动效收集
  • 原文地址:https://www.cnblogs.com/lyj-gyq/p/9100363.html
Copyright © 2011-2022 走看看