Spring MVC請(qǐng)求處理流程
對(duì)Web應(yīng)用來(lái)說(shuō),表示層是不可或缺的重要環(huán)節(jié)。傳統(tǒng)的Struts2框架就是一個(gè)優(yōu)秀的Web框架。除了Struts2框架外,Spring框架也為表示層提供了一個(gè)優(yōu)秀的Web框架,即Spring MVC。由于Spring MVC采用了松耦合可插拔組件結(jié)構(gòu),因此比其他MVC框架具有更大的擴(kuò)展性和靈活性。通過(guò)注解,Spring MVC使得POJO成為處理用戶請(qǐng)求的控制器,無(wú)需實(shí)現(xiàn)任何接口。
一、環(huán)境及準(zhǔn)備
Eclipse(http://www.eclipse.org/)
Tomcat9.0.4(http://tomcat.apache.org/)
jdk9.0.4(http://www.oracle.com/technetwork/java/javase/downloads/index.html)
Spring-framework-5.0.4.RELEASE-dist.zip(http://repo.springsource.org/libs-release-local/)
二、創(chuàng)建項(xiàng)目
在Eclipse中,創(chuàng)建一個(gè)名為“springmvc-1”的Web項(xiàng)目,并把相關(guān)jar包添加到項(xiàng)目的WebContent\WEB-INF\lib路徑中,并添加到項(xiàng)目的構(gòu)建路徑中。如下圖所示:
??????

項(xiàng)目最終的目錄結(jié)構(gòu),如下圖所示:

三、前端控制器DispatcherServlet
在web.xml文件中,配置Spring MVC的前端控制器DispatcherServlet。Spring MVC是基于Servlet的框架,DispatcherServlet是整個(gè)Spring MVC框架的核心,它負(fù)責(zé)接收請(qǐng)求并將其分派給相應(yīng)的處理器處理,關(guān)鍵配置代碼如下:
??????

上述配置的目的在于,讓Web容器使用Spring MVC的DispatcherServlet,并通過(guò)設(shè)置url-pattern為“/”,將所有的URL請(qǐng)求都映射到這個(gè)前端控制器DispatcherServlet。在配置DispatcherServlet的時(shí)候,通過(guò)設(shè)置contextConfigLocation參數(shù)來(lái)指定Spring MVC配置文件的位置,此處使用Spring 資源路徑的方式進(jìn)行指定。
四、創(chuàng)建Spring MVC的配置文件
在項(xiàng)目springmvc-1的src目錄下創(chuàng)建Spring MVC配置文件springmvc.xml,在該配置文件中,我們使用Spring MVC最簡(jiǎn)單的配置方式進(jìn)行配置,主要配置如下:
??????

在springmvc.xml配置文件中,首先要引入beans、aop、context和mvc命名空間,然后主要完成配置處理器和視圖解析器。在springmvc.xml配置文件中,并沒(méi)有配置處理器映射和處理器適配器,當(dāng)用戶沒(méi)有配置這兩項(xiàng)時(shí),Spring會(huì)使用默認(rèn)的處理器映射和處理器適配器來(lái)處理請(qǐng)求。
五、創(chuàng)建Handler處理器(Controller)
? 在項(xiàng)目的src目錄下創(chuàng)建包c(diǎn)om.springmvc.controller,在包中創(chuàng)建類(lèi)HelloController.java,并實(shí)現(xiàn)Controller接口中的handleRequest方法,用來(lái)處理hello請(qǐng)求,代碼如下:
??????

上訴代碼中,HelloController是一個(gè)實(shí)現(xiàn)了Controller接口的控制器,它可以處理一個(gè)單一的請(qǐng)求動(dòng)作。handleRequest是Controller接口必須實(shí)現(xiàn)的方法,該方法必須返回一個(gè)包含視圖名或視圖名和模型的ModelAndView對(duì)象,該對(duì)象既包含視圖信息,也包含模型數(shù)據(jù)信息。這樣Spring MVC就可以使用視圖對(duì)模型數(shù)據(jù)進(jìn)行解析。本例返回的模型中包含一個(gè)名為“msg”的字符串對(duì)象,返回的視圖路徑為 /ch06/first.jsp,因此,請(qǐng)求將被轉(zhuǎn)發(fā)到 ch06路徑下的 first.jsp頁(yè)面。
ModelAndView對(duì)象代表Spring MVC中呈現(xiàn)視圖界面時(shí)所使用的Model(模型數(shù)據(jù))和View(邏輯視圖名稱(chēng))。由于Java一次只能返回一個(gè)對(duì)象,所以ModelAndView的作用就是封裝這兩個(gè)對(duì)象,一次返回我們所需要的Model和View。當(dāng)然,返回的模型和視圖也都是可選的,在一些情況下,模型中沒(méi)有任何數(shù)據(jù),那么只返回視圖即可,或者只返回模型,讓Spring MVC根據(jù)請(qǐng)求URL來(lái)決定。以后還會(huì)對(duì)ModelAndView對(duì)象進(jìn)行講解。
六、創(chuàng)建視圖頁(yè)面
??在項(xiàng)目WebContext路徑下創(chuàng)建ch06文件夾,在ch06文件夾中創(chuàng)建JSP視圖頁(yè)面first.jsp,并在該視圖頁(yè)面上通過(guò)EL表達(dá)式輸出“msg”中的信息,代碼如下:
??

七、部署項(xiàng)目,啟動(dòng)Tomcat服務(wù)器進(jìn)行測(cè)試
將項(xiàng)目springmvc-1發(fā)布到Tomcat中,并啟動(dòng)Tomcat服務(wù)器,在瀏覽器地址中訪問(wèn)http://localhost:8080/springmvc-1/hello,其運(yùn)行效果如下圖所示:

從上圖可以看到,瀏覽器中已經(jīng)顯示出了模型對(duì)象的字符串信息,控制臺(tái)窗口中輸出了“Hello Springmvc_1”提示,這也就說(shuō)明程序執(zhí)行成功。
使用MVC框架就應(yīng)該遵守MVC思想,MVC框架不贊成瀏覽器直接訪問(wèn)Web應(yīng)用的視圖頁(yè)面,用戶的所有請(qǐng)求都只應(yīng)向控制器發(fā)送,由控制器調(diào)用模型組件、視圖組件向用戶呈現(xiàn)數(shù)據(jù)。
八、總結(jié)
當(dāng)用戶發(fā)送URL請(qǐng)求http://localhost:8080/springmvc-1/hello時(shí),根據(jù)web.xml中對(duì)DispatcherServlet(前端控制器)的配置,該請(qǐng)求被DispatcherServlet(前端控制器)截獲,并根據(jù)HandleMapping(處理器映射器)找到處理相應(yīng)請(qǐng)求的Handler處理器(Controller控制器,這里便是HelloController);Controller處理完成后,返回ModelAndView對(duì)象;該對(duì)象告訴DispatcherServlet(前端控制器)需要通過(guò)哪個(gè)視圖來(lái)進(jìn)行數(shù)據(jù)模型的展示,DispatcherServlet(前端控制器)根據(jù)視圖解析器把Controller返回的邏輯視圖名渲染成真正的視圖并輸出,呈現(xiàn)給用戶。
九、深入了解Spring MVC請(qǐng)求處理流程
? Spring MVC請(qǐng)求處理流程如下圖所示,我們一步一步來(lái)看它的處理流程。
??

(1)用戶通過(guò)客戶端向服務(wù)器發(fā)起一個(gè)request請(qǐng)求,此請(qǐng)求會(huì)被前端控制器(DispatcherServlet)攔截。
(2)前端控制器(DispatcherServlet)請(qǐng)求處理器映射器(HandleMapping)去查找處理器(Handler),可以依據(jù)XML配置或注解去查找。
(3)處理器映射器(HandleMapping)根據(jù)請(qǐng)求的URL找到具體的處理器(Handler),生成處理器對(duì)象及處理器攔截器(如果有則生成),并返回給前端控制器。
(4)前端控制器(DispatcherServlet)請(qǐng)求處理器適配器(HandlerAdapter)去執(zhí)行相應(yīng)的處理器(Handler,常稱(chēng)為Controller)。
(5)處理器適配器(HandlerAdapter)會(huì)調(diào)用并執(zhí)行處理器(Handler),這里的處理器(Handler)指的是程序中編寫(xiě)的Controller類(lèi),也被稱(chēng)為后端控制器。請(qǐng)求信息在真正到達(dá)處理器(Handler)的處理方法之前的這段時(shí)間內(nèi),Spring MVC還完成了很多工作。
消息轉(zhuǎn)換:將請(qǐng)求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對(duì)象,將對(duì)象轉(zhuǎn)換為指定的響應(yīng)信息。
數(shù)據(jù)轉(zhuǎn)換:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換,如String轉(zhuǎn)換成Integer、Double等。
數(shù)據(jù)格式化:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)格式化,如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等。
數(shù)據(jù)驗(yàn)證:驗(yàn)證數(shù)據(jù)的有效性(長(zhǎng)度、格式等),驗(yàn)證結(jié)果存儲(chǔ)到BindingResult或Error中。
(6)處理器(Handler)執(zhí)行完畢后,也就是Controller執(zhí)行完畢后,會(huì)返回給處理器適配器(HandlerAdapter)一個(gè)ModelAndView對(duì)象(Spring MVC底層對(duì)象),該對(duì)象中會(huì)包含View視圖信息或包含View視圖信息和Model數(shù)據(jù)模型信息。
(7)處理器適配器(HandlerAdapter)接收到ModelAndView對(duì)象后,將其返回給前端控制器(DispatcherServlet)。
(8)前端控制器(DispatcherServlet)接收到ModelAndView對(duì)象后,選擇一個(gè)合適的視圖解析器(ViewReslover)對(duì)視圖進(jìn)行解析。
(9)視圖解析器(ViewReslover)解析后,會(huì)根據(jù)View視圖信息配置到相應(yīng)的視圖結(jié)果,反饋給前端控制器(DispatcherServlet)。
(10)前端控制器(DispatcherServlet)收到View視圖后,進(jìn)行視圖渲染,將模型數(shù)據(jù)(在ModelAndView對(duì)象中)填充到request域。
(11)前端控制器(DispatcherServlet)向用戶響應(yīng)結(jié)果。
以上就是Spring MVC的整個(gè)請(qǐng)求處理流程,其中用到的組件有前端控制器(DispatcherServlet)、處理器映射器(HandleMapping)、處理器適配器(HandlerAdapter)、Handler處理器(Controller)、視圖解析器(ViewReslover)、視圖(View)。其中,前端控制器(DispatcherServlet)、處理器映射器(HandleMapping)、處理器映射器(HandleMapping)、視圖解析器(ViewReslover)對(duì)象的工作是在框架內(nèi)部執(zhí)行的,開(kāi)發(fā)人員并不需要關(guān)心這些對(duì)象內(nèi)部的實(shí)現(xiàn)過(guò)程,只需要配置前端控制器(DispatcherServlet),完成Handler處理器(Controller)中的業(yè)務(wù)處理,并在視圖(View)中展示相應(yīng)信息即可。
