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