先描述一个场景:

你到一个机关办事,一个是办事窗口的那个人很不客气地说,这个事你别找我,你找xxx窗口,然后你自己跑到xxx窗口,那个窗口的人直接给你办了;还有一个是窗口的人和你说,你等下,他自己跑去找另一个人沟通一番,然后跑回来给你办了。

前者是redirect重定向,后者便是forward转发。

重定向redirect和转发forward的流程图如下:

(1)客户端跳转--重定向redirect

客户端向服务器发送请求时,服务器返回一个“去访问其他链接”的响应,客户端根据此响应,第二次去访问服务器,服务器给出最终的响应,所以总共有两次请求。客户端跳转时,地址栏会发生改变。

使用response的rsendRedirect方法:

  重定向格式:response.sendRedirect("path");

(2)服务端跳转--转发forward

客户端向服务器发送请求时,服务器发现当前资源给不出回应,服务器需要在内部请求另一个资源的跳转,然后给出响应,这属于1次请求,由于服务器跳转与否客户端并不知道,所以地址栏的url并不会改变。

使用requestDispatcher对象:

  转发格式:request.getRequestDispatcher("path").forward(response,request)

使用jsp动作元素:

  <jsp:forward page=""/>

(3)转发与重定向的区别

1.地址栏 
转发:不变,不会显示出转向的地址 
重定向:会显示转向之后的地址

2.请求 

转发:一次请求
重定向:至少提交了两次请求

3.数据 
转发:对request对象的信息不会丢失,因此可以在多个页面交互过程中实现请求数据的共享 
重定向:request信息将丢失

4.原理 

请求转发为服务器内部跳转,跳转一次,客户端接收结果,而不改变url地址,而请求重定向则跳转两次,既将结果返回给客户端,又使客户端的url地址改变。 

请求转发为为内部跳转,页面请求的对象一直存在,请求重定向则会结束上个页面的请求。

请求转发的传参使用request对象方法setAttribute(“name”,value),请求重定向只需使用url传参即可。

(4)实例:

例子1:

转发:在返回值前面加"forward:"

从第一个转发到其他的处理器,是不需要写传递的数据的,因为数据共享

 

 

重定向:在返回值前面加"redirect:

 

实例2:

1、常规用法,返回一个View

 1 @RequestMapping(value="/testa", method=RequestMethod.GET)
 2 public String inputData(){
 3     return "testa"; //Spring框架找到对应的View并渲染
 4 }
 5 
 6 @RequestMapping(value="/testa", method=RequestMethod.POST)
 7 public String outputData(HttpServletRequest request){
 8     String userName = request.getParameter("name");
 9     String password = request.getParameter("pwd");
10     request.setAttribute("name", userName);
11     request.setAttribute("pwd", password);
12     return "testb"; //Spring框架找到对应的View并渲染
13 }

 

打开testa网页:

 

 

 

 

输入用户名:spring,密码:spring:

 

 

 

 

点击登陆按钮,页面变为如下:

 

再次刷新,谷歌浏览器提示重新提交表单。

 

对比图片,发现浏览器的输入框中URL不变,但是不同情况下显示不同的View。跳转时Model共享(表单会被重复提交)。

2、转发(forward)

 1 @RequestMapping(value="/testa", method=RequestMethod.GET)
 2 public String inputData(){
 3     return "testa"; //Spring框架找到对应的View并渲染
 4 }
 5 
 6 @RequestMapping(value="/testa", method=RequestMethod.POST)
 7 public String outputData(HttpServletRequest request){
 8     String userName = request.getParameter("name");
 9     String password = request.getParameter("pwd");
10     request.setAttribute("name", userName);
11     request.setAttribute("pwd", password);
12     //转发到 /testb 的Controller方法(即outputDataX)上
13     return "forward:/testb"; 
14 }
15 
16 @RequestMapping(value="/testb", method=RequestMethod.POST)
17 public String outputDataX(HttpServletRequest request){
18     return "testb";
19 }


打开testa网页:

 

 

 

输入用户名:spring,密码:spring:

 

 

 

点击登陆按钮,页面变为如下:

 

 

 

调试分析:forward后面跟一个资源。当程序运行到return “forward:/testb”时,会执行会执行该资源对应的方法outputDataX。
另外转发时,浏览器的URL不变。

再次刷新,谷歌浏览器提示重新提交表单。

 

 

 

3、重定向(redirect)

 1 @RequestMapping(value="/testa", method=RequestMethod.GET)
 2 public String inputData(){
 3     return "testa"; //Spring框架找到对应的View并渲染
 4 }
 5 
 6 @RequestMapping(value="/testa", method=RequestMethod.POST)
 7 public String outputData(HttpServletRequest request){
 8     String userName = request.getParameter("name");
 9     String password = request.getParameter("pwd");
10     request.setAttribute("name", userName);
11     request.setAttribute("pwd", password);
12     //重定向到 /testb 的Controller方法(即outputDataY)上
13     return "redirect:/testb"; 
14 }
15 
16 @RequestMapping(value="/testb", method=RequestMethod.POST)
17 public String outputDataX(HttpServletRequest request){
18     return "testb";
19 }
20 
21 @RequestMapping(value="/testb", method=RequestMethod.GET)
22 public String outputDataY(HttpServletRequest request){
23     return "testb";
24 }


打开testa网页:

 

 

 

输入用户名:spring,密码:spring:

 

 

 

点击登陆按钮,页面变为如下:

 

 

 

调试分析:redirect后面跟一个资源。当执行到return “redirect:/testb”时,会执行该资源对应个方法outputDataY。由于重定向Model不共享,所以页面无数据显示。
另外重定向后浏览器的输入框中URL也发生变化。

刷新后,谷歌浏览器没有提示重新提交表单

 

 

 

总结:
常说的可以通过redirect: URL防止重复提交表单,就是上面过程的意思。
原理是对于redirect而言,Request的attribute不会被传递,放到session中,session在跳到页面后马上移除对象。所以你刷新一下后这个值就会丢掉。

如果你希望Request的attribute被传递,可以使用RedirectAttributes类。

 1 @RequestMapping(value="/testa", method=RequestMethod.GET)
 2 public String inputData(){
 3     return "testa"; //Spring框架找到对应的View并渲染
 4 }
 5 
 6 @RequestMapping(value="/testa", method=RequestMethod.POST)
 7 public String outputData(HttpServletRequest request, RedirectAttributes     redirectAttributes){
 8     String userName = request.getParameter("name");
 9     String password = request.getParameter("pwd");
10     request.setAttribute("name", userName);
11     request.setAttribute("pwd", password);
12     //重定向到 /testb 的Controller方法(即outputDataY)上
13     //重定向传递参数的两种方法
14     redirectAttributes.addAttribute("name", userName);
15     redirectAttributes.addFlashAttribute("pwd", password);
16 
17     return "redirect:/testb"; 
18 }
19 
20 @RequestMapping(value="/testb", method=RequestMethod.POST)
21 public String outputDataX(HttpServletRequest request){
22     return "testb";
23 }
24 
25 @RequestMapping(value="/testb", method=RequestMethod.GET)
26 public String outputDataY(HttpServletRequest request){
27     String userName = request.getParameter("name");
28     request.setAttribute("name", userName);
29     return "testb";
30 }

 

运行如下:

 

 

 

上面示例了使用RedirectAttributes传递参数的两种方法:
1. 使用RedirectAttributes类的addAttribute方法传递参数会跟随在URL后面,如上图谷歌浏览器所示,URL为http://localhost:8080/testb?name=spring
2. 使用RedirectAttributes类的addFlashAttribute方法传递参数不会跟随在URL后面,会把该参数值暂时保存于session,待重定向URL获取该参数后从session中移除,这里的redirect必须是方法映射路径,jsp无效。你会发现redirect后的jsp页面中pwd只会出现一次,刷新后pwd再也不会出现了。下图为刷新后的结果,密码pwd显示为空。这验证了上面说的,pwd在被访问后就会从session中移除。对于防止重复提交可以使用此方法。

 

参考链接:

https://ask.csdn.net/questions/376121

https://blog.csdn.net/jiangshangchunjiezi/article/details/88998809

https://blog.csdn.net/webzhuce/article/details/54564608

posted on 2019-09-15 13:30  小白coder  阅读(2373)  评论(1编辑  收藏  举报