先描述一個場景:web
你到一個機關辦事,一個是辦事窗口的那我的很不客氣地說,這個事你別找我,你找xxx窗口,而後你本身跑到xxx窗口,那個窗口的人直接給你辦了;還有一個是窗口的人和你說,你等下,他本身跑去找另外一我的溝通一番,而後跑回來給你辦了。spring
前者是redirect重定向,後者即是forward轉發。瀏覽器
重定向redirect和轉發forward的流程圖以下:服務器
(1)客戶端跳轉--重定向redirectsession
客戶端向服務器發送請求時,服務器返回一個「去訪問其餘連接」的響應,客戶端根據此響應,第二次去訪問服務器,服務器給出最終的響應,因此總共有兩次請求。客戶端跳轉時,地址欄會發生改變。app
使用response的rsendRedirect方法:框架
重定向格式:response.sendRedirect("path");jsp
(2)服務端跳轉--轉發forwardurl
客戶端向服務器發送請求時,服務器發現當前資源給不出迴應,服務器須要在內部請求另外一個資源的跳轉,而後給出響應,這屬於1次請求,因爲服務器跳轉與否客戶端並不知道,因此地址欄的url並不會改變。spa
使用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:
一、常規用法,返回一個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共享(表單會被重複提交)。
二、轉發(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不變。
再次刷新,谷歌瀏覽器提示從新提交表單。
三、重定向(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