Spring MVC 整體介紹
Spring MVC 整體介紹
大學(xué)時(shí)寫(xiě)的的文章,當(dāng)時(shí)文章水平略差,大家見(jiàn)諒。 Spring MVC 是以servlet 為核心進(jìn)行實(shí)現(xiàn)的,統(tǒng)一入口進(jìn)入拿到請(qǐng)求后,做一次路由,找到對(duì)應(yīng)的controller及對(duì)應(yīng)的RequestMapping,完成邏輯的后,返回對(duì)應(yīng)的視圖或者數(shù)據(jù)元,如果是順道完成視圖的解析,返回對(duì)應(yīng)html,完成響應(yīng)。
開(kāi)發(fā)步驟: 1、建立Spring 工程,引入對(duì)應(yīng)Spring MVC 所需要的Jar。
2、創(chuàng)建web.xml 文件,指定dispacherServlet,然后指定攔截的請(qǐng)求規(guī)則,比如說(shuō) *.do,再配置對(duì)應(yīng)的listener,還有spring 依賴(lài)的bean的配置文件 3、創(chuàng)建springMVC-servlet.xml 類(lèi)似于這樣的一個(gè)配置文件,設(shè)置啟用注解,設(shè)置對(duì)應(yīng)掃描的包,然后指定頁(yè)面存在的位置,指定前綴后綴什么 4、在對(duì)應(yīng)目錄下創(chuàng)建一個(gè)controller 類(lèi),并指定對(duì)應(yīng)注解,創(chuàng)建對(duì)應(yīng)RequestMapping 注解的函數(shù),設(shè)置URI。 5、編寫(xiě)對(duì)應(yīng)邏輯。 6、部署&運(yùn)行 內(nèi)部處理流程: 1、dispacher Servlet 攔截到外部所有的請(qǐng)求 2、根據(jù)HandlerMapping找到對(duì)應(yīng)的Handler,并將一堆***和Handler封裝至HandlerExecutionChain 3、帶著Handler 找到對(duì)應(yīng)的HandlerAdapter,完成對(duì)應(yīng)的邏輯處理。 4、帶著具體的Model&View返回 5、首先通過(guò)ViewResolver對(duì)于視圖進(jìn)行解析,并完成 對(duì)應(yīng)的視圖渲染,反饋給Dispacher Servlet。
6、**dispacher Servlet 完成響應(yīng) 這就是Spring MVC 中的一個(gè)簡(jiǎn)要流程。 這里的Handler 是需要我們手動(dòng)實(shí)現(xiàn)邏輯的,也就具體的controller、然后ModleAndView 也是我們開(kāi)發(fā)中所接觸的ModelAndView,具體的渲染和解析的過(guò)程其實(shí)就是將對(duì)應(yīng)視圖變?yōu)榍岸丝勺R(shí)別HTML 文檔的形式,過(guò)程中將對(duì)應(yīng)的對(duì)象信息解析進(jìn)去就OK了。 具體的看后續(xù)操作~ 這里介紹的主要是核心的分發(fā)器dispacherServlet,在說(shuō)之前先來(lái)看一看常規(guī)的servlet。
public interface Servlet { } sevlet 是Java 在Java web開(kāi)發(fā)中定義的一個(gè)規(guī)范,任何一個(gè)可以處理外部用戶(hù)請(qǐng)求的應(yīng)用組件都需要實(shí)現(xiàn)這個(gè)接口(即作為一種servlet 存在)。 public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { 這是GenericServlet,一種servlet的通用實(shí)現(xiàn),提供了servlet應(yīng)該有的基礎(chǔ)功能。 我們常用的是HTTP servlet,一種基于HTTP協(xié)議對(duì)于GenericServlet實(shí)現(xiàn)的Servlet,能夠?qū)τ谕獠縃TTP請(qǐng)求進(jìn)行對(duì)應(yīng)的處理并且完成對(duì)應(yīng)的響應(yīng)。
并且針對(duì)各種HTTP 請(qǐng)求原語(yǔ)實(shí)現(xiàn)了對(duì)應(yīng)的處理方法(具體來(lái)說(shuō)是要求使用者自己必須實(shí)現(xiàn)) DispacherServlet 就是一種HTTP servlet ,它實(shí)現(xiàn)了對(duì)于所有符合規(guī)則的的HTTP請(qǐng)求進(jìn)行攔截,并對(duì)具有handler的請(qǐng)求完成具體的邏輯。
個(gè)人對(duì)于spring mvc框架的理解
以下我的個(gè)人理解加上**上的所查閱資料,對(duì)于spring mvc框架的一些總結(jié),不足之處還望指出 在web模型中,MVC是一種很流行的框架,通過(guò)把Model,View,Controller分離,把較為復(fù)雜的web應(yīng)用分成邏輯清晰的幾部分,是為了簡(jiǎn)化開(kāi)發(fā),減少出錯(cuò),同時(shí)也為了組內(nèi)開(kāi)發(fā)人員之間的配合。總之就是一種分層工作的辦法。
(1) 用戶(hù)通過(guò)瀏覽器向服務(wù)器發(fā)送請(qǐng)求,請(qǐng)求被springmvc的前端控制器DispatcherServlet攔截; (2) DispatcherServlet攔截到請(qǐng)求后,會(huì)調(diào)用HandlerMapping處理映射器; (3) 處理器映射器根據(jù)請(qǐng)求URL找到具體的處理器,生成處理器對(duì)象及處理器***(如果有則生成)一并返回給調(diào)用處理器DispatcherServlet; (4)DispatcherServlet會(huì)通過(guò)返回信息選擇合適的HanderAdapter(處理器適配器); (5)HanderAdapter會(huì)調(diào)用并執(zhí)行Handler(處理器),這里的處理器值的就是程序中編寫(xiě)的Controller類(lèi),也被稱(chēng)之為后端控制器; (6)Controller執(zhí)行完成后,會(huì)返回一個(gè)ModelAndView對(duì)象,該對(duì)象中包含視圖名或包含模型和視圖名 (7)HandlerAdapter將ModelAndView對(duì)象返回給DispatcherServlet; (8)DispatcherServlet會(huì)根據(jù)ModelAndView對(duì)象選擇一個(gè)合適的ViewReslover(視圖解析器) (9)ViewReslover解析后,會(huì)向DispatcherServlet中返回具體的View (10)DispatcherServlet對(duì)view進(jìn)行渲染(即將模型數(shù)據(jù)填充至視圖中) (11)視圖渲染結(jié)果會(huì)返回給客戶(hù)端瀏覽器顯示 (1)DispatcherServlet接口:Spring提供的前端控制器,所有的請(qǐng)求都有經(jīng)過(guò)它來(lái)統(tǒng)一分發(fā)。
在DispatcherServlet將請(qǐng)求分發(fā)給Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具體的Controller。 (2)HandlerMapping接口:能夠完成客戶(hù)請(qǐng)求到Controller映射。 (3)Controller接口:需要為并發(fā)用戶(hù)處理上述請(qǐng)求,因此實(shí)現(xiàn)Controller接口時(shí),必須保證線程安全并且可重用。Controller將處理用戶(hù)請(qǐng)求,這和Struts Action扮演的角色是一致的。
一旦Controller處理完用戶(hù)請(qǐng)求,則返回ModelAndView對(duì)象給DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和視圖(View)。 從宏觀角度考慮,DispatcherServlet是整個(gè)Web應(yīng)用的控制器;從微觀考慮,Controller是單個(gè)Http請(qǐng)求處理過(guò)程中的控制器,而ModelAndView是Http請(qǐng)求過(guò)程中返回的模型(Model)和視圖(View)。 (4)ViewResolver接口:Spring提供的視圖解析器(ViewResolver)在Web應(yīng)用中查找View對(duì)象,從而將相應(yīng)結(jié)果渲染給客戶(hù)。
是整個(gè)Spring MVC的核心。它負(fù)責(zé)接收HTTP請(qǐng)求組織協(xié)調(diào)Spring MVC的各個(gè)組成部分。其主要工作有以下三項(xiàng): (1)截獲符合特定格式的URL請(qǐng)求。
(2)初始化DispatcherServlet上下文對(duì)應(yīng)WebApplicationContext,并將其與業(yè)務(wù)層、持久化層的WebApplicationContext建立關(guān)聯(lián)。 (3)初始化Spring MVC的各個(gè)組成組件,并裝配到DispatcherServlet中。
spring mvc的優(yōu)點(diǎn)是什么
1、spring3開(kāi)發(fā)效率高于struts;2、spring3 mvc可以認(rèn)為已經(jīng)****零配置;3、struts2是類(lèi)級(jí)別的攔截, 一個(gè)類(lèi)對(duì)應(yīng)一個(gè)request上下文,springmvc是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)request上下文,而方法同時(shí)又跟一個(gè)url對(duì)應(yīng)。所以說(shuō)從架構(gòu)本身上 spring3 mvc就容易實(shí)現(xiàn)restful url,而struts2的架構(gòu)實(shí)現(xiàn)起來(lái)要費(fèi)勁。
Spring MVC 面試總結(jié)
SpringMVC的核心就是DispatcherServlet,DispatcherServlet實(shí)質(zhì)也是一個(gè)HttpServlet,繼承 了FrameworkServlet,實(shí)現(xiàn) ApplicationContextAware 接口,繼承 HttpServletBean 抽象類(lèi) , 負(fù)責(zé)初始化 Spring Servlet WebApplicationContext 容器,同時(shí)該類(lèi)覆寫(xiě)了 doGet、doPost 等方法,并將所有類(lèi)型的請(qǐng)求委托給 doService 方法去處理,doService 是一個(gè)抽象方法,需要子類(lèi)實(shí)現(xiàn),DispatcherServlet負(fù)責(zé)初始化 Spring MVC 的各個(gè)組件,以及處理客戶(hù)端的請(qǐng)求,協(xié)調(diào)各個(gè)組件工作WebApplicationContext 是實(shí)現(xiàn) ApplicationContext 接口的子類(lèi),專(zhuān)門(mén)為 WEB 應(yīng)用準(zhǔn)備的 它允許從相對(duì)于 Web 根目錄的路徑中加載配置文件,完成初始化 Spring MVC 組件的工作。 從 WebApplicationContext 中,可以獲取 ServletContext 引用,整個(gè) Web 應(yīng)用上下文對(duì)象將作為屬性放置在 ServletContext 中,以便 Web 應(yīng)用環(huán)境可以訪問(wèn) Spring 上下文。
ContextLoaderListener 繼承 ContextLoader 類(lèi),實(shí)現(xiàn) Servlet 容器啟動(dòng)和關(guān)閉時(shí),分別初始化和銷(xiāo)毀 WebApplicationContext 容器,WebApplicationContext 有兩處 Servlet 3.0 新增的一個(gè)接口ServletContainerInitializer?,配合@HandlesTypes 注解來(lái)指定希望被處理的類(lèi),容器在啟動(dòng)時(shí)使用 JAR 服務(wù) 的時(shí)候會(huì)通過(guò)SPI機(jī)制發(fā)現(xiàn)?ServletContainerInitializer?的實(shí)現(xiàn)類(lèi),并且容器將 WEB-INF/lib 目錄下 JAR 包中的類(lèi)都交給該類(lèi)的 onStartup() 方法處理,實(shí)現(xiàn)的 onStartup 方法中可以向 ServletContext 對(duì)象(Servlet 上下文)添加之前在 web.xml 中配置的 Filter和 Servlet,這樣一來(lái)就可以去除 web.xml 文件了?SpringMVC的實(shí)現(xiàn)類(lèi)?SpringServletContainerInitializer?就是實(shí)現(xiàn)了ServletContainerInitializer接口,負(fù)責(zé)初始化web環(huán)境,SpringServletContainerInitializer把所有的初始化任務(wù)委托給WebApplicationInitializer這個(gè)接口的實(shí)現(xiàn)類(lèi),其中AbstractDispatcherServletInitializer便是創(chuàng)建DispatcherServlet 的關(guān)鍵類(lèi)SpringBoot 是通過(guò)?org.springframework.boot.web.embedded.tomcat.TomcatStarter?這個(gè)類(lèi)進(jìn)行初始化流程的,TomcatStarter同樣也是實(shí)現(xiàn)了ServletContainerInitializer接口,通過(guò)構(gòu)造方法傳入的ServletContextInitializer去初始化Web環(huán)境,其中ServletWebServerApplicationContext?負(fù)責(zé)?加載Filter、Servlet、Listener ServletWebServerApplicationContext 的 onRefresh() 方法觸發(fā)配置了一個(gè)匿名的 ServletContextInitializer 這個(gè)匿名的 ServletContextInitializer 的 onStartup 方**去容器中搜索到了所有的 RegisterBean 并按照順序加載到 ServletContext 中 這個(gè)匿名的 ServletContextInitializer 最終傳遞給 TomcatStarter,由 TomcatStarter 的 onStartup 方法去觸發(fā) ServletContextInitializer 的 onStartup 方法,最終完成裝配 注冊(cè)方式一: Servlet3.0 注解(@WebServlet,@WebFilter,@WebListener) +@ServletComponentScan , 在啟動(dòng)類(lèi)上面添加?@ServletComponentScan?注解去掃描到這些注解 注冊(cè)方式二: RegistrationBean,比如?ServletRegistrationBean 和 FilterRegistrationBean 都繼成 RegistrationBean,它是 SpringBoot 中廣泛應(yīng)用的一個(gè)注冊(cè)類(lèi),負(fù)責(zé)把 Servlet,F(xiàn)ilter,Listener 給容器化,使它們被 Spring 托管,并且完成自身對(duì) Web 容器的注冊(cè)用戶(hù)的瀏覽器發(fā)送一個(gè)請(qǐng)求,這個(gè)請(qǐng)求經(jīng)過(guò)互聯(lián)網(wǎng)到達(dá)了我們的服務(wù)器。
Servlet 容器首先接待了這個(gè)請(qǐng)求,并將該請(qǐng)求委托給?DispatcherServlet?進(jìn)行處理。 1.?DispatcherServlet 主要通過(guò) dispatch 這個(gè)方法去處理整個(gè)流程,這個(gè)流程他會(huì)先去通過(guò) HandlerMapping 的getHandler方法得到一個(gè)HandlerExecutionChain對(duì)象 HandlerMapping 就是一個(gè)接口,里面就只有一個(gè)方法就叫g(shù)etHandler,他有很多實(shí)現(xiàn)類(lèi),但是大體主要通過(guò)兩種方式獲得Handler 一種是 AbstracHandlerMethodMapping?和 AbstractUrlHandlerMapping ,一個(gè)是基于 Method 進(jìn)行匹配的,比如@RequestMapping注解,一個(gè)是基于 URL 進(jìn)行匹配,我們平常用的最多的還是RequestMappingHandlerMapping,這個(gè)就是 AbstracHandlerMethodMapping?的子類(lèi) HandlerExecutionChain 這個(gè)對(duì)象就是包含了***和處理器對(duì)象,這個(gè)處理器對(duì)象是object類(lèi)型的,對(duì)象比如說(shuō),我們平常通過(guò)在方法上標(biāo)記@RequestMapping注解,然后呢他這個(gè)對(duì)象就是HandlerMethod 類(lèi)型, 這個(gè)?HandlerMethod封裝了很多屬性,在訪問(wèn)請(qǐng)求方法的時(shí)候可以方便的訪問(wèn)到方法、方法參數(shù)、方法上的注解、所屬類(lèi)等并且對(duì)方法參數(shù)封裝處理,也可以方便的訪問(wèn)到方法參數(shù)的注解等信息。***呢,就是實(shí)現(xiàn)了HandlerInterceptor接口的類(lèi),就是在執(zhí)行方法之前和執(zhí)行方法之后進(jìn)行一些處理 2.?拿到這個(gè) HandlerExecutionChain 對(duì)象之后呢,還要找一個(gè)HandlerAdapter 適配器,他通過(guò)遍歷 HandlerAdapter 組件,判斷是否支持處理該?handler?處理器,支持則返回該 HandlerAdapter 組件,這個(gè)HandlerAdapter組件負(fù)責(zé)處理執(zhí)行整個(gè)流程,參數(shù)的解析,方法的執(zhí)行,返回值的處理,都是在他里面完成的, 像我們平時(shí)用的最多的還是RequestMappingHandlerAdapter類(lèi),他就是執(zhí)行 HandlerMethod 類(lèi)型的處理器,也就是通過(guò)?@RequestMapping?等注解標(biāo)注的方法 3. 然后呢通過(guò)執(zhí)行HandlerAdapter的handle方法,會(huì)給我們返回一個(gè)ModelAndView 對(duì)象,這個(gè)呢就是數(shù)據(jù)和視圖地址,然后呢就會(huì)調(diào)用processDispatchResult這個(gè)方法去解析視圖,這里面他會(huì)通過(guò)render這個(gè)方法進(jìn)行頁(yè)面渲染邏輯,這里面就會(huì)交給viewResolvers去處理,但是我們平常開(kāi)發(fā)都是標(biāo)注了ResponseBody注解,所以在HandlerAdapter這里面會(huì)將我們返回的結(jié)果直接將數(shù)據(jù)通過(guò)HttpServletResponse.write寫(xiě)進(jìn)去,**直接返回?Spring MVC的***的實(shí)現(xiàn)了HandlerInterceptor接口 , 里面主要有三個(gè)方法?preHandle,postHandle,afterCompletion,分別是前置處理,后置處理和已完成處理 這個(gè)HandlerInterceptor呢,他會(huì)在在HanderMapping的子類(lèi) AbstractHandlerMapping 中的?getHandler 方法中去獲取,一般是在獲取完handler處理器后然后會(huì)去和HandlerInterceptor去組裝成 HandlerExecutionChain 對(duì)象, HandlerInterceptor***呢會(huì)在AbstractHandlerMapping?initApplicationContext ()方法中初始化完成的,因?yàn)檫@個(gè)方法是重寫(xiě)了父類(lèi) ApplicationObjectSupport 的initApplicationContext()ApplicationObjectSupport最上層的接口ApplicationContextAware中的 setApplicationContext ,所以他會(huì)在初始化該ben的時(shí)候調(diào)用setApplicationContext這個(gè)方法,然后這個(gè)方法將 interceptors 初始化成 HandlerInterceptor 類(lèi)型,添加到?adaptedInterceptors 中 HandlerMapping 組件,請(qǐng)求的 處理器匹配器 ,負(fù)責(zé)為請(qǐng)求找到合適的?HandlerExecutionChain?處理器執(zhí)行鏈,包含處理器(handler)和***們(interceptors),下面先說(shuō) AbstractHandlerMapping AbstractHandlerMapping 抽象類(lèi),一個(gè)基類(lèi),實(shí)現(xiàn)了“為請(qǐng)求找到合適的?HandlerExecutionChain?處理器執(zhí)行鏈”對(duì)應(yīng)的的骨架邏輯,而暴露?getHandlerInternal()?抽象方法,交由子類(lèi)實(shí)現(xiàn)。 AbstractUrlHandlerMappingAbstractHandlerMethodMapping 因?yàn)槠渲刑幚砥鞯膶?shí)現(xiàn)有多種,例如通過(guò)實(shí)現(xiàn) Controller 接口、HttpRequestHandler 接口,或者使用?@RequestMapping?注解將方法作為一個(gè)處理器等。
Spring MVC 就無(wú)法直接執(zhí)行這個(gè)處理器,所以這里需要一個(gè)處理器適配器,由它去執(zhí)行處理器, HandlerAdapter 接口也就三個(gè)方法,一個(gè)是判斷是否支持該處理器的,一個(gè)是執(zhí)行處理器返回ModelAndView的,還有一個(gè)是返回請(qǐng)求的**更新時(shí)間的 HttpRequestHandlerAdapter :執(zhí)行實(shí)現(xiàn)了 HttpRequestHandler 接口的處理器 SimpleControllerHandlerAdapter :執(zhí)行實(shí)現(xiàn)了 Controller 接口的處理器 SimpleServletHandlerAdapter :執(zhí)行實(shí)現(xiàn)了 Servlet 接口的處理器 RequestMappingHandlerAdapter : 執(zhí)行 HandlerMethod 類(lèi)型的處理器,也就是通過(guò)?@RequestMapping?等注解標(biāo)注的方法,主要說(shuō)說(shuō)RequestMappingHandlerAdapter的執(zhí)行流程: 1. 會(huì)先創(chuàng)建ServletInvocableHandlerMethod并且設(shè)置一些屬性,這個(gè)是對(duì)HandlerMethod?處理器的封裝,然后通過(guò)這個(gè)對(duì)象的invokeAndHandle方法去執(zhí)行 2?然后需要通過(guò)?HandlerMethodArgumentResolver?對(duì)象進(jìn)行參數(shù)解析 3?在通過(guò)反射執(zhí)行對(duì)應(yīng)的 Method 方法對(duì)象 4?**通過(guò)?HandlerMethodReturnValueHandler?對(duì)象對(duì)執(zhí)行結(jié)果進(jìn)行處理,設(shè)置到?response?響應(yīng)中,生成對(duì)應(yīng)的 ModelAndView 對(duì)象 ServletInvocableHandlerMethod 封裝?HandlerMethod?處理器對(duì)象,它還包含?HandlerMethodArgumentResolver?參數(shù)解析器和?HandlerMethodReturnValueHandler?返回值處理器等組件 參數(shù)解析器,先說(shuō)說(shuō)他是怎么處理的吧, 在ServletInvocableHandlerMethod解析參數(shù)會(huì)先用到一個(gè)HandlerMethodArgumentResolverComposite對(duì)象,這也是一個(gè)實(shí)現(xiàn)HandlerMethodArgumentResolver接口的對(duì)象,他呢是一個(gè)組合對(duì)象,里面就包含了很多的參數(shù)解析器,他會(huì)遍歷所有的參數(shù)解析器去調(diào)用supportsParameter這個(gè)方法去看是否支持解析該參數(shù),如果支持呢他就會(huì)返回這個(gè)參數(shù)解析器,不支持就會(huì)給返回一個(gè)IllegalStateException的異常,然后呢就會(huì)調(diào)用resolveArgument去解析這個(gè)參數(shù),像解析參數(shù)處理器的就非常多了,常見(jiàn)的有: RequestParamMethodArgumentResolver: 基于?@RequestParam?注解的 也可以不帶 PathVariableMethodArgumentResolver : 基于?@PathVariable?注解的 ServletModelAttributeMethodProcessor :基于ModelAttribute注解的,處理實(shí)體類(lèi),也可以不帶 RequestResponseBodyMethodProcessor: 基于@RequestBody注解的 在轉(zhuǎn)換的過(guò)程中呢還有個(gè)參數(shù)轉(zhuǎn)換器,比如啊我們從瀏覽器發(fā)過(guò)來(lái)的請(qǐng)求都是text類(lèi)型的,所以必須要把這這些類(lèi)型轉(zhuǎn)換成我們的目標(biāo)類(lèi)型,比如Date,Number啊這些類(lèi)型,都需要通過(guò)轉(zhuǎn)換器去完成,WebDataBinder 利用它里面的 Converters 將請(qǐng)求數(shù)據(jù)轉(zhuǎn)成指定的數(shù)據(jù)類(lèi)型。再次封裝到JavaBean中,拿到這些處理好的值,直接通過(guò)反射調(diào)用我們寫(xiě)好的方法獲得拿到需要返回的值就好了 HandlerMethodReturnValueHandler?返回值處理器將返回結(jié)果設(shè)置到響應(yīng)中,或者設(shè)置相應(yīng)的 Model 和 View 用于后續(xù)的視圖渲染。這個(gè)接口也就兩個(gè)方法,一個(gè)是判斷是否支持該返回類(lèi)型的,還有一個(gè)就是處理返回值的 RequestResponseBodyMethodProcessor :?負(fù)責(zé)處理@ResponseBody注解的返回值,現(xiàn)在前后端分離,后端基本是提供 Restful API,最常用的就是他,RequestResponseBodyMethodProcessor中還有個(gè)最重要的就是MessageConverters內(nèi)容協(xié)商,利用 MessageConverters將返回的數(shù)據(jù) 寫(xiě)為json,他 =會(huì)根據(jù)請(qǐng)求頭Accept去看瀏覽器接收什么樣的數(shù)據(jù)類(lèi)型,在根據(jù)MessageConverters實(shí)現(xiàn)類(lèi)的MediaType這個(gè)類(lèi)去和你匹配看自己能支持那些內(nèi)容類(lèi)型的數(shù)據(jù),那你瀏覽器需要json就會(huì)得到MappingJackson2HttpMessageConverter這個(gè)對(duì)象,然后把對(duì)象轉(zhuǎn)成json寫(xiě)到response中 ViewNameMethodReturnValueHandler :?適用于前后端未分離,Controller 返回視圖名的場(chǎng)景,例如 JSP、thymeleaf模板引擎就用這個(gè)處理器異常解析器,將處理器執(zhí)行請(qǐng)求時(shí)發(fā)生的異常,解析成對(duì)應(yīng)的 ModelAndView 結(jié)果,大致就是通過(guò)@ControllerAdvice+@ExceptionHandler注解處理全局異常,底層就是HandlerExceptionResolver 接口支持的,其中一個(gè)實(shí)現(xiàn)類(lèi) ExceptionHandlerExceptionResolver 會(huì)在初始化的時(shí)候去掃描 掃描 @ControllerAdvice 注解的 Bean 們?nèi)缓笳业接?@ExceptionHandler 注解的方法,則添加到 exceptionHandlerAdviceCache 中,執(zhí)行的時(shí)候他里面也有參數(shù)解析器和返回值處理器,處理完了之后也會(huì)返回ModelAndView對(duì)象視圖解析器,根據(jù)視圖名和國(guó)際化,獲得最終的視圖 View 對(duì)象。
Spring MVC 執(zhí)行完處理器后生成一個(gè) ModelAndView 對(duì)象,如果該對(duì)象不為?null?并且有對(duì)應(yīng)的?viewName,那么就需要通過(guò)?ViewResolver?根據(jù)?viewName?解析出對(duì)應(yīng)的 View 對(duì)象MultipartResolver?組件,內(nèi)容類(lèi)型(?Content-Type?)為?multipart/*?的請(qǐng)求的解析器,主要解析文件上傳的請(qǐng)求。例如,MultipartResolver?會(huì)將 HttpServletRequest 封裝成?MultipartHttpServletRequest?對(duì)象, DispatcherServlet?Spring MVC 的核心組件,是請(qǐng)求的入口,負(fù)責(zé)協(xié)調(diào)各個(gè)組件工作 MultipartResolver 內(nèi)容類(lèi)型(?Content-Type?)為?multipart/*?的請(qǐng)求的解析器,例如解析處理文件上傳的請(qǐng)求,便于獲取參數(shù)信息以及上傳的文件 HandlerMapping 請(qǐng)求的處理器匹配器,負(fù)責(zé)為請(qǐng)求找到合適的?HandlerExecutionChain?處理器執(zhí)行鏈,包含處理器(handler)和***們(interceptors) HandlerAdapter 處理器的適配器。因?yàn)樘幚砥?handler?的類(lèi)型是 Object 類(lèi)型,需要有一個(gè)調(diào)用者來(lái)實(shí)現(xiàn)?handler?是怎么被執(zhí)行。
Spring 中的處理器的百科實(shí)現(xiàn)多變,比如用戶(hù)處理器可以實(shí)現(xiàn) Controller 接口、HttpRequestHandler 接口,也可以用?@RequestMapping?注解將方法作為一個(gè)處理器等,這就導(dǎo)致 Spring MVC 無(wú)法直接執(zhí)行這個(gè)處理器。所以這里需要一個(gè)處理器適配器,由它去執(zhí)行處理器 HandlerExceptionResolver 處理器異常解析器,將處理器(?handler?)執(zhí)行時(shí)發(fā)生的異常,解析( 轉(zhuǎn)換 )成對(duì)應(yīng)的 ModelAndView 結(jié)果 RequestToViewNameTranslator 視圖名稱(chēng)轉(zhuǎn)換器,用于解析出請(qǐng)求的默認(rèn)視圖名 LocaleResolver 本地化(國(guó)際化)解析器,提供國(guó)際化支持 ThemeResolver 主題解析器,提供可設(shè)置應(yīng)用整體樣式風(fēng)格的支持 ViewResolver 視圖解析器,根據(jù)視圖名和國(guó)際化,獲得最終的視圖 View 對(duì)象 FlashMapManager FlashMap 管理器,負(fù)責(zé)重定向時(shí),保存參數(shù)至臨時(shí)存儲(chǔ)(默認(rèn) Session)@Controller 注解有什么用? @Controller?注解標(biāo)記一個(gè)類(lèi)為 Spring Web MVC 控制器 Controller。Spring MVC 會(huì)將掃描到該注解的類(lèi),然后掃描這個(gè)類(lèi)下面帶有?@RequestMapping?注解的方法,根據(jù)注解信息,為這個(gè)方法生成一個(gè)對(duì)應(yīng)的 處理器 對(duì)象,在上面的 HandlerMapping 和 HandlerAdapter組件中講到過(guò)。
當(dāng)然,除了添加?@Controller?注解這種方式以外,你還可以實(shí)現(xiàn) Spring MVC 提供的?Controller?或者?HttpRequestHandler?接口,對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)也會(huì)被作為一個(gè) 處理器 對(duì)象 @RequestMapping 注解有什么用? @RequestMapping?注解,在上面已經(jīng)講過(guò)了,配置 處理器 的 HTTP 請(qǐng)求方法,URI等信息,這樣才能將請(qǐng)求和方法進(jìn)行映射。這個(gè)注解可以作用于類(lèi)上面,也可以作用于方法上面,在類(lèi)上面一般是配置這個(gè) 控制器 的 URI 前綴 @RestController 和 @Controller 有什么區(qū)別? @RestController?注解,在?@Controller?基礎(chǔ)上,增加了?@ResponseBody?注解,更加適合目前前后端分離的架構(gòu)下,提供 Restful API ,返回例如 JSON 數(shù)據(jù)格式。當(dāng)然,返回什么樣的數(shù)據(jù)格式,根據(jù)客戶(hù)端的?ACCEPT?請(qǐng)求頭來(lái)決定。 @RequestMapping 和 @GetMapping 注解的不同之處在哪里? @RequestMapping:可注解在類(lèi)和方法上;@GetMapping?僅可注冊(cè)在方法上 @RequestMapping:可進(jìn)行 GET、POST、PUT、DELETE 等請(qǐng)求方法;@GetMapping?是?@RequestMapping?的 GET 請(qǐng)求方法的特例,目的是為了提高清晰度。
@RequestParam 和 @PathVariable 兩個(gè)注解的區(qū)別 兩個(gè)注解都用于方法參數(shù),獲取參數(shù)值的方式不同,@RequestParam?注解的參數(shù)從請(qǐng)求攜帶的參數(shù)中獲取,而?@PathVariable?注解從請(qǐng)求的 URI 中獲取 返回 JSON 格式使用什么注解? 可以使用 @ResponseBody 注解,或者使用包含?@ResponseBody?注解的 @RestController 注解。 當(dāng)然,還是需要配合相應(yīng)的支持 JSON 格式化的 HttpMessageConverter 實(shí)現(xiàn)類(lèi)。