Spring MVC 轉(zhuǎn)發(fā)與重定向
1. 前言
WEB 應用程序的交互模式通過請求包與響應包來完成,請求包一般由瀏覽器構(gòu)建,并發(fā)送給服務器端。服務器端解析請求包,并根據(jù)具體的業(yè)務邏輯處理請求包中的數(shù)據(jù),并構(gòu)建響應包回應請求方。
響應包的實體部分中的內(nèi)容可以由控制器的方法決定,或者說由需求來決定。根據(jù)響應包中的內(nèi)容不同,可以分兩者響應方式:
- 轉(zhuǎn)發(fā):響應包直接包含響應給瀏覽器的數(shù)據(jù);
- 重定向:響應包僅包含數(shù)據(jù)視圖的地址。
本節(jié)課程將向大家講解 Spring MVC 中如何實現(xiàn)轉(zhuǎn)發(fā)和重定向。本章節(jié)的重點是了解轉(zhuǎn)發(fā)和重定向的本質(zhì)。
2. 響應的本質(zhì)
Spring MVC 項目中的用戶控制器用來處理用戶的請求,無論處理的結(jié)果如何,都需要給用戶一個響應,HTTP 響應包可以說是這個響應結(jié)果的載體。
理論上講,用戶控制器處理完請求,得到的結(jié)果數(shù)據(jù)可以直接寫入到響應包中。
@Controller
public class ResponseAction {
@RequestMapping("/response01")
public void response01(HttpServletResponse response) throws IOException {
//發(fā)送給客戶端的響應數(shù)據(jù)
String hello="hello";
PrintWriter out =response.getWriter();
out.write(hello);
out.close();
}
}
把需要響應給客戶端的數(shù)據(jù)寫入響應包中便是響應的本質(zhì)。
如果僅僅只是把數(shù)據(jù)發(fā)送給客戶端,數(shù)據(jù)在瀏覽器中顯示時,出來的樣式會過于簡單、甚至丑陋。要解決這個問題,也好辦,發(fā)送數(shù)據(jù)時,也附帶發(fā)送數(shù)據(jù)格式。
Tips:如果客戶端只需要純數(shù)據(jù),如 JSON 格式,則可以直接使用上面的方法。
修改上面的響應數(shù)據(jù):
String hello="<font color=\"red\">hello</font>";
這時,在瀏覽器中不僅能看到數(shù)據(jù),還能用設計好的樣式顯示出來。初期 WEB 開發(fā),便采用了這種 “數(shù)據(jù) + 樣式” 的方式。因初期頁面中數(shù)據(jù)并不是很多,人為對于頁面無素顯示也沒有多大需求。
但是,隨著項目功能越來越大,數(shù)據(jù)量成倍增加,比如說商城首頁,需要顯示當前登錄者信息、商品信息、推薦的商品信息、用戶瀏覽信息…… 并且用戶對最終顯示結(jié)果也提出了更多要求,如美觀、大方、整潔……
如果還是如前面一樣,把數(shù)據(jù)和 HTML 一起編織在一起,然后響應給客戶端,代碼將變得丑陋不堪。
新的解決方案是采用組件化開發(fā)思想:控制器處理數(shù)據(jù),視圖組件提供模板樣式用來顯示最終數(shù)據(jù)。
所以在構(gòu)建響應包時,控制器需要 2 方面信息:
- 數(shù)據(jù):由控制器返回;
- 視圖:由視圖解析器組件維護。
Spring MVC 提供數(shù)據(jù)模型組件充當數(shù)據(jù)和視圖之間的橋梁。
- 控制器先把處理后的數(shù)據(jù)保存到數(shù)據(jù)模型中;
- 找到視圖,由視圖從數(shù)據(jù)模型中取得數(shù)據(jù),并顯示在視圖中。
重定向和轉(zhuǎn)發(fā)的區(qū)別在于尋找視圖的方式。
2.1 轉(zhuǎn)發(fā)
如下面的實例:
@RequestMapping("/response02")
public String response02(ModelMap model) throws IOException {
//發(fā)送給客戶端的響應數(shù)據(jù)
String hello="Hello";
model.addAttribute("data", hello);
return "hello";
}
上面代碼是一個典型的 Spring MVC 控制器代碼:
- 變量 hello 中保存的就是要發(fā)送給瀏覽器的數(shù)據(jù)。
- ModelMap 類型的數(shù)據(jù)模型可以說是一個中間載體,用來臨時保存 hello 中的數(shù)據(jù);
- return 后面的 “hello” 是視圖的邏輯名,由視圖解析器解析并找到真正的頁面。
下面是一個標準的視圖模板,頁面中已經(jīng)提供了樣式,只等數(shù)據(jù)的到來。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<div style="color:red"> ${data} </div>
</body>
</html>
有了這些信息后,視圖解析器把數(shù)據(jù)和視圖合二為一后進行渲染,得到純 HTML 后寫入響應包,發(fā)送給瀏覽器。
這便于轉(zhuǎn)發(fā)或者叫派發(fā)。默認情況下,控制器的響應方式使用的是轉(zhuǎn)發(fā)。
轉(zhuǎn)發(fā)是在一次請求中一氣呵成完成的。如上代碼,在瀏覽器輸入請求:http://localhost:8888/sm-demo/response02。
服務端響應包中的數(shù)據(jù)這就是響應給客戶端的最終數(shù)據(jù)。
Tips: Spring MVC 的整個請求和響應過程是由多個組件協(xié)作完成的,這里不深究細節(jié)。
2.2 重定向
Spring MVC 中使用重定向很簡單,只需要在返回值中添加 redirect 關(guān)鍵字。
@RequestMapping("/response03")
public String response03(ModelMap model) throws IOException {
//發(fā)送給客戶端的響應數(shù)據(jù)
String hello="Hello";
model.addAttribute("data", hello);
return "redirect:/hello";
}
重定向和轉(zhuǎn)發(fā)的本質(zhì)區(qū)別在于如何找到視圖。轉(zhuǎn)發(fā)是控制器自己找的,也就是在服務器端找的。
重定向則是先把視圖地址寫入響應包,然后發(fā)送瀏覽器,意思是說,瀏覽器,麻煩你自己找一下。瀏覽器獲取到響應包中的地址后再發(fā)送一次請求,找到視圖,然后,把數(shù)據(jù)模型中的數(shù)據(jù)讀出來顯示在頁面中。
相比較轉(zhuǎn)發(fā),重定向會多一次請求,也意味著數(shù)據(jù)模型中的數(shù)據(jù)需要在跨請求間被解析到。另外,視圖文件必須放置在瀏覽器能訪問到的位置。如果視圖文件放在 WEB-INF 目錄下,則重定向是不能訪問到的。
3. 小結(jié)
本章節(jié)和大家一起講解 Spring MVC 框架如何實現(xiàn)轉(zhuǎn)發(fā)和重定向,從實現(xiàn)角度來講,沒有太多難度。默認情況下就是轉(zhuǎn)發(fā),加上 redirect 關(guān)鍵字后就能實現(xiàn)重定向。需要注意的是,redirect 后面需要指定視圖文件的完整路徑。
轉(zhuǎn)發(fā)和重定向都是一種響應方式,其內(nèi)在區(qū)別就在于一個是尋找視圖的方式是不同的。一個是控制器幫著找,一個是瀏覽器通過再次發(fā)起請求尋找,所以,重定向和轉(zhuǎn)發(fā)對數(shù)據(jù)模型的作用域要求是不同的。