Web UI项目中, 很多 Spring controller 视图函数直接返回 html 页面, 还有一些视图函数是要重定向或转发到其他的 url 上.

redirect 和 forward的区别:

重定向 redirect: 完整的重定向包含两次request-response过程, 第一次是访问原始url, 第二次是服务器通知客户端访问重定向后的url. 重定向完成后, 浏览器的地址是重定向后的url, 而不是原始的url.
    重定向的使用场景: 因为重定向会修改浏览器地址, 所以 form 提交应该使用重定向, 以免用户刷新页面导致form重复提交.

转发 forward: 完整的转发仅包含一次 request-response 过程, 用户发出request后, 服务器端视图函数先处理自己的逻辑, 然后在服务器端有调用另一个视图函数, 最后将response返回给浏览器.

==============================
转发 forward
==============================
在Spring MVC 中, 构建forward 目标有两种方式:
1. 以字符串的形式构建目标url, url 需要加上 forward: 前缀
2. 使用 ModelAndView 对象来设置转发的forward目标, viewName 可以省略 forward: 前缀, viewName 应该是目标url, 而不是目标视图的函数名.
传参方式:
1. 以字符串的形式构建目标url, 可以使用 query variable的格式拼url
2. 使用 ModelAndView 对象来增加 attribute Object, 其结果也是在拼接url. 
取参的方式: 可以使用 @RequestParam 来取参.

==============================
重定向 redirect
==============================
redirect 目标有三种构建方式
1. 使用 redirect: 前缀url方式构建目标url
2. 使用 RedirectView 类型指定目标, 推荐使用这个,
3. 使用 ModelAndView 类型指定目标, ModelAndView 视图名默认是forward, 所以对于redirect, 需要加上 redirect: 前缀

传参和取参方式:
1. 传参: 以字符串的形式构建目标url, 可以使用 query variable的格式拼url. 取参: @RequestParam()来fetch
2. 传参: redirectAttributes.addAttribute() 加的attr. 取参: @RequestParam()来fetch
3. 传参: redirectAttributes.addFlashAttribute() 加的attr. 取参: @ModelAttribute()来fetch

Flash attribute的特点:
1. addFlashAttribute() 可以是任意类型的数据(不局限在String等基本类型), addAttribute()只能加基本类型的参数.
2. addFlashAttribute() 加的 attr, 不会出现在url 地址栏上.
3. addFlashAttribute() 加的 attr, 一旦fetch后, 就会自动清空, 非常适合 form 提交后 feedback Message.

==============================
示例代码
==============================
-----------------------------
pom.xml 和 application.properties
-----------------------------

  1. <dependency>
  2. <groupId>io.pebbletemplates</groupId>
  3. <artifactId>pebble-spring-boot-2-starter</artifactId>
  4. <version>3.0.5</version>
  5. </dependency>
  1. # application.properties file
  2. pebble.prefix=/templates/
  3. pebble.suffix=.html
  4. pebble.content-type=text/html
  5. pebble.cache=false
  6. pebble.encoding=UTF-
  7. pebble.defaultLocale=null
  8. pebble.strictVariables=false

-----------------------------
java 代码
-----------------------------

  1. @Controller
  2. @RequestMapping("/")
  3. public class DemoController {
  4.  
  5. /*
  6. * forward 示例: 以字符串的形式构建目标url, url 需要加上 forward: 前缀
  7. * */
  8. @RequestMapping("/forwardTest1")
  9. public String forwardTest1() {
  10. return "forward:/forwardTarget?param1=v1&param2=v2";
  11. }
  12.  
  13. /*
  14. * forward 示例: 使用 ModelAndView() 设置转发的目标url
  15. * */
  16. @RequestMapping("/forwardTest2")
  17. public ModelAndView forwardTest2() {
  18. ModelAndView mav=new ModelAndView("/forwardTarget"); // 绝对路径OK
  19. //ModelAndView mav=new ModelAndView("forwardTarget"); // 相对路径也OK
  20. mav.addObject("param1", "value1");
  21. mav.addObject("param2", "value2");
  22. return mav ;
  23. }
  24.  
  25. @RequestMapping("/forwardTarget")
  26. public String forwardTargetView(Model model, @RequestParam("param1") String param1,
  27. @RequestParam("param2") String param2) {
  28. model.addAttribute("param1", param1);
  29. model.addAttribute("param2", param2);
  30. return "forwardTarget";
  31. }
  32.  
  33. /*
  34. * redirect 目标有三种构建方式
  35. * 1. 使用 redirect: 前缀url方式构建目标url
  36. * 2. 使用 RedirectView 类型指定目标
  37. * 3. 使用 ModelAndView 类型指定目标, ModelAndView 视图名默认是forward, 所以对于redirect, 需要加上 redirect: 前缀
  38. * */
  39. @RequestMapping("/noParamRedirect")
  40. public RedirectView noParamTest() {
  41. RedirectView redirectTarget = new RedirectView();
  42. redirectTarget.setContextRelative(true);
  43. redirectTarget.setUrl("noParamTarget");
  44. return redirectTarget;
  45. }
  46.  
  47. @RequestMapping("/noParamTarget")
  48. public String redirectTarget() {
  49. return "noParamTarget";
  50. }
  51.  
  52. @RequestMapping("/withParamRedirect")
  53. public RedirectView withParamRedirect(RedirectAttributes redirectAttributes) {
  54. RedirectView redirectTarget = new RedirectView();
  55. redirectTarget.setContextRelative(true);
  56. redirectTarget.setUrl("withParamTarget");
  57.  
  58. redirectAttributes.addAttribute("param1", "value1");
  59. redirectAttributes.addAttribute("param2", "value2");
  60. return redirectTarget;
  61. }
  62.  
  63. @RequestMapping("/withParamTarget")
  64. public String withParamTarget(Model model, @RequestParam("param1") String param1,
  65. @RequestParam("param2") String param2) {
  66. model.addAttribute("param1", param1);
  67. model.addAttribute("param2", param2);
  68. return "withParamTarget";
  69. }
  70.  
  71. @RequestMapping("/withFlashRedirect")
  72. public RedirectView withFlashTest(RedirectAttributes redirectAttributes) {
  73. RedirectView redirectTarget = new RedirectView();
  74. redirectTarget.setContextRelative(true);
  75. redirectTarget.setUrl("withFlashTarget");
  76.  
  77. redirectAttributes.addAttribute("param", "value");
  78. redirectAttributes.addFlashAttribute("flashParam", "flashValue");
  79. return redirectTarget;
  80. }
  81.  
  82. /*
  83. * redirectAttributes.addAttribute加的attr, 使用 @RequestParam()来fetch
  84. * redirectAttributes.addFlashAttribute()加的attr, 使用 @ModelAttribute()来fetch
  85. * */
  86. @RequestMapping("/withFlashTarget")
  87. public String withFlashTarget(Model model, @RequestParam("param") String param,
  88. @ModelAttribute("flashParam") String flashParam) {
  89. model.addAttribute("param", param);
  90. model.addAttribute("flashParam", flashParam);
  91. return "withFlashTarget";
  92. }
  93.  
  94. @GetMapping("/input")
  95. public String input() {
  96. return "input";
  97. }
  98.  
  99. /*
  100. * form 提交后, 如果form数据有问题, 使用redirectAttributes.addFlashAttribute()加上 flash message.
  101. * addFlashAttribute()可以是任意类型的数据(不局限在String等基本类型)
  102. * addFlashAttribute() 加的 attr, 不会出现在url 地址栏上.
  103. * addFlashAttribute() 加的 attr, 一旦fetch后, 就会自动清空, 非常适合 form 提交后 feedback Message.
  104. * */
  105. @PostMapping("/submit")
  106. public RedirectView submit(RedirectAttributes redirectAttributes) {
  107. boolean passed = false;
  108. if (passed==false) {
  109. RedirectView redirectTarget = new RedirectView();
  110. redirectTarget.setContextRelative(true);
  111. redirectTarget.setUrl("input");
  112. redirectAttributes.addFlashAttribute("errorMessage", "some error information here");
  113. return redirectTarget;
  114. }else {
  115. RedirectView redirectTarget = new RedirectView();
  116. redirectTarget.setContextRelative(true);
  117. redirectTarget.setUrl("inputOK");
  118. return redirectTarget;
  119. }
  120. }
  121. }

==============================
Html 代码
==============================

-------------------------------
input.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  6. <meta name="description" content="">
  7. <meta name="author" content="">
  8. <title> </title>
  9. <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
  10. <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
  11. </head>
  12. <body>
  13. <div class="container">
  14. <form class="form-signin" method="post" action="/submit">
  15. <h2 class="form-signin-heading">Please input</h2>
  16. {% if errorMessage is not empty %}
  17. <div class="alert alert-danger" role="alert">{{errorMessage}}</div>
  18. {% endif %}
  19. <p>
  20. <label for="username" class="sr-only">Username</label>
  21. <input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus>
  22. </p>
  23. <button class="btn btn-lg btn-primary btn-block" type="submit">submit</button>
  24. </form>
  25. </div >
  26. </body>
  27. </html>

-------------------------------
inputOK.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title> </title>
  5. </head>
  6. <body>
  7. <div class="container">
  8. <h1>inputOK</h1>
  9. </div >
  10. </body>
  11. </html>

-------------------------------
forwardTarget.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>{{param1}} &nbsp; {{param2}} </title>
  5. </head>
  6. <body>
  7. <h1>forwardTarget</h1>
  8. </body>
  9. </html>

-------------------------------
withParamTarget.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>{{param1}} &nbsp; {{param2}} </title>
  5. </head>
  6. <body>
  7. <h1>withParamTarget</h1>
  8. </body>
  9. </html>

-------------------------------
noParamTarget.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>{{systemName}} &nbsp; {{version}} </title>
  5. </head>
  6. <body>
  7. <h1>noParamTarget</h1>
  8. </body>
  9. </html>

-------------------------------
withFlashTarget.html
-------------------------------

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>{{param}} &nbsp; {{flashParam}} </title>
  5. </head>
  6. <body>
  7. <h1>withFlashTarget</h1>
  8. </body>
  9. </html>

==============================
效果截图
==============================

转发后的url还是原始请求url,  http://www.localhost:8080/forwardTest1

重定向的地址会发生改变, 请求地址  http://localhost:8080/withParamRedirect , 结果地址:

form提交验证的示例:  http://localhost:8080/input

开始时的GET 请求截图:

form 提交后的截图:

SpringBoot系列: url重定向和转发的更多相关文章

  1. springboot项目的重定向和转发

    下面是idea软件创建的项目目录,这里总结了一下转发与重定向的问题,详解如下. 首先解释一下每个文件夹的作用,如果你是用的是idea创建的springboot项目,会在项目创建的一开始resource ...

  2. SpringBoot系列教程web篇之重定向

    原文地址: SpringBoot系列教程web篇之重定向 前面介绍了spring web篇数据返回的几种常用姿势,当我们在相应一个http请求时,除了直接返回数据之外,还有另一种常见的case -&g ...

  3. 请求转发 和 URL 重定向

    五 请求转发 和 URL 重定向 1 请求转发和重定向 干什么用? 是我们在java后台servlet中 由一个servlet跳转到 另一个 servlet/jsp 要使用的技术 前端发送请求到后台 ...

  4. 请求转发和URL重定向的原理和区别

    一.请求转发和重定向是在java后台servlet中,由一个servlet跳转到另一个servlet/jsp要使用的技术 使用方法 请求转发  req.getResquestDispatcher(se ...

  5. SpringMVC系列(九)自定义视图、重定向、转发

    一.自定义视图 1. 自定义一个视图HelloView.java,使用@Component注解交给Spring IOC容器处理 package com.study.springmvc.views; i ...

  6. JSTL、请求转发和URL重定向

    JSTL 为什么要使用JSTL? 因为在JSP中写JAVA代码很麻烦,而JSTL可以简化在JSp中写JAva代码的流程 如何使用JSTL? 准备工作: ①将JSTL依赖的jar包导入工程的WEB-IN ...

  7. SpringBoot系列教程web篇之过滤器Filter使用指南

    web三大组件之一Filter,可以说是很多小伙伴学习java web时最早接触的知识点了,然而学得早不代表就用得多.基本上,如果不是让你从0到1写一个web应用(或者说即便从0到1写一个web应用) ...

  8. SpringBoot系列: SpringBoot Web项目中使用Shiro

    注意点有:1. 不要启用 spring-boot-devtools, 如果启用 devtools 后, 不管是热启动还是手工重启, devtools总是试图重新恢复之前的session数据, 很有可能 ...

  9. springBoot系列-->springBoot注解大全

    一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfiguration ...

随机推荐

  1. (转载)Python之道1-环境搭建与pycharm的配置django安装及MySQL数据库配置

    近期做那个python的开发,今天就来简单的写一下开发路线的安装及配置, 开发路线 Python3.6.1+Pycharm5.0.6+Django1.11+MySQL5.7.18 1-安装Python ...

  2. Spring Boot 正常启动后访问Controller提示404

    问题描述 今天重新在搭建Spring Boot项目的时候遇到访问Controller报404错误,之前在搭建的时候没怎么注意这块.新创建项目成功后,作为项目启动类的Application在com.bl ...

  3. Scrapy案例01-爬取传智播客主页上的老师信息

    目录 1. 新建scrapy项目 2. 爬虫文件: 2.1. 查看需要爬取内容存在哪里: 2.2. 设置item需要保存的数据变量 2.3. 创建爬虫文件 2.4. 保存数据 2.5. yield的用 ...

  4. python离线安装包

    一.用download命令离线下载包  *.whl , 这个方法好像python3.7以上才能用 那么我的requirement.txt内容就是: django==1.8.11 simplejson= ...

  5. gradle构建项目失败:Unzipping /home/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zip to /home/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9

    Unzipping /home/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3-all.zip to ...

  6. Luogu5176 公约数 莫比乌斯反演、线性筛

    传送门 好像是我们联考时候的题目? 一个结论:\(\gcd(ij,ik,jk) \times \gcd(i,j,k) = \gcd(i,j) \times \gcd(i,k) \times \gcd( ...

  7. 循环语句--do...while

    do...while循环 格式: 执行流程 执行顺序:①③④>②③④>②③④…②不满足为止. ①负责完成循环变量初始化. ②负责判断是否满足循环条件,不满足则跳出循环. ③具体执行的语句 ...

  8. [2019BUAA软工助教]第0次个人作业

    [2019BUAA软工助教]第0次个人作业 一.前言 我认为人生就是一次次地从<存在>到<光明>. 二.软件工程师的成长 博客索引 同学们在上这门课的时候基本都是大三,觉得在大 ...

  9. Day5 Numerical simulation of optical wave propagation之通过随机介质(如大气湍流)的传播(一)

    一 分步光束传播方法 到目前为止,人们已经设计出传播算法,用于模拟通过真空和通过可用光线矩阵描述的简单光学系统的传播. 其中分步光束传播方法除了描述上述传播过程,还有更复杂的应用,包括:部分时间和空间 ...

  10. Oracle物化视图的创建及使用

    oracle物化视图 一.oracle物化视图基本概念  物化视图首先需要创建物化视图日志,  oracle依据用户创建的物化视图日志来创建物化视图日志表,  物化视图日志表的名称为mlog$_后面跟 ...