SpringMVC介紹
為什么要使用springMVC?
很多應用程序的問題在於處理業務數據和顯示業務數據的視圖的對象之間存在緊密耦合。通常,更新業務對象的命令都是從視圖本身發起的,使視圖對任何業務對象更改都有高度敏感性。而且,當多個視圖依賴於同一個業務對象時是沒有靈活性的。
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
MVC設計模型
MVC 是一種著名的設計模式,特別是在 Web 應用程序領域。模式全都是關於將包含業務數據的模塊與顯示模塊的視圖解耦的。這是怎樣發生的?視圖(例如,JSP 頁面)怎樣能夠與其模型(例如,包含數據的 JavaBean)解耦?記得這句格言么?一個層次的重定向幾乎可以解決計算機業中的所有問題。確實,在模型和視圖之間引入重定向層可以解決問題。此重定向層是控制器。控制器將接收請求,執行更新模型的操作,然后通知視圖關於模型更改的消息。依賴於模型的狀態並且依賴於請求的控制器可以決定要顯示哪個視圖。
springMVC的強大之處
1.Spring MVC 實現了即用的 MVC 的核心概念。它為控制器和處理程序提供了大量與此模式相關的功能。並且當向 MVC 添加反轉控制(Inversion of Control,IoC)時,它使應用程序高度解耦,提供了通過簡單的配置更改即可動態更改組件的靈活性。Spring MVC 為您提供了完全控制應用程序的各個方面的力量。
2.Spring 的 Web MVC 模塊是圍繞 DispatcherServlet 而設計的。DispatcherServlet 給處理程序分派請求,執行視圖解析,並且處理語言環境和主題解析,此外還為上傳文件提供支持。
3.DispatcherServlet 通過使用處理程序映射來決定哪一個處理程序應當處理傳入的請求。處理程序映射只是用於標識使用哪一個處理程序來處理特定 URL 模式的映射。處理程序是只有一種方法 ModelAndView handleRequest(request,response) 的控制器接口的實現。Spring 還有一些可用的高級處理程序實現;其中一個重要的高級處理程序實現是 SimpleFormController,它提供了將命令對象綁定到表單、對其執行驗證等功能。
4.您已經在本系列教程的先前教程中使用了 DispatcherServlet 和簡單的處理程序。在下一個部分中,將使用 SimpleFormController 並說明 Spring MVC 提供的各種即用功能。
springMVC優勢
1、清晰的角色划分:前端控制器(DispatcherServlet)、請求到處理器映射(HandlerMapping)、處理器適配器(HandlerAdapter)、視圖解析器(ViewResolver)、處理器或頁面控制器(Controller)、驗證器( Validator)、命令對象(Command 請求參數綁定到的對象就叫命令對象)、表單對象(Form Object 提供給表單展示和提交到的對象就叫表單對象)。
2、分工明確,而且擴展點相當靈活,可以很容易擴展,雖然幾乎不需要;
3、由於命令對象就是一個POJO,無需繼承框架特定API,可以使用命令對象直接作為業務對象;
4、和Spring 其他框架無縫集成,是其它Web框架所不具備的;
5、可適配,通過HandlerAdapter可以支持任意的類作為處理器;
6、可定制性,HandlerMapping、ViewResolver等能夠非常簡單的定制;
7、功能強大的數據驗證、格式化、綁定機制;
8、利用Spring提供的Mock對象能夠非常簡單的進行Web層單元測試;
9、本地化、主題的解析的支持,使我們更容易進行國際化和主題的切換。
10、強大的JSP標簽庫,使JSP編寫更容易。
………………還有比如RESTful風格的支持、簡單的文件上傳、約定大於配置的契約式編程支持、基於注解的零配置支持等等。
springMVC的運行原理
架構圖

首先讓我們了解下 MVC(Model-View-Controller)三元組的概念:
Model(模型):數據模型,提供要展示的數據,因此包含數據和行為,可以認為是領域模型或 JavaBean 組件(包含數據和行為),不過現在一般都分離開來:Value Object(數據) 和 服務層(行為)。也就是模型提供了模型數據查詢和模型數據的狀態更新等功能,包括數據和業務。
領域模型
javaBean組件等價於 域模型層 + 業務邏輯層 + 持久層
View(視圖):負責進行模型的展示,一般就是我們見到的用戶界面,客戶想看到的東西。
Controller(控制器):接收用戶請求,委托給模型進行處理(狀態改變),處理完畢后把返回的模型數據返回給視圖,
由視圖負責展示。 也就是說控制器做了個調度員的工作,。
Springmvc運行原理流程

核心架構的具體流程步驟如下:
1、 首先用戶發送請求——>DispatcherServlet,前端控制器收到請求后自己不進行處理,而是委托給其他的解析器進行處理,作為統一訪問點,進行全局的流程控制;
2、DispatcherServlet——>HandlerMapping,HandlerMapping將會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器)對象,通過這種策略模式,很容易添加新的映射策略;
3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter將會把處理器包裝為適配器,從而支持多種類型的處理器,即適配器設計模式的應用,從而很容易支持很多類型的處理器;
4、 HandlerAdapter——>處理器功能處理方法的調用,HandlerAdapter將會根據適配的結果調用真正的處理器的功能處理方法,完成功能處理;並返回一個ModelAndView對象(包含模型數據、邏輯視圖名);
5、 ModelAndView的邏輯視圖名——> ViewResolver, ViewResolver將把邏輯視圖名解析為具體的View,通過這種策略模式,很容易更換其他視圖技術;
6、 View——>渲染,View會根據傳進來的Model模型數據進行渲染,此處的Model實際是一個Map數據結構,因此很容易支持其他視圖技術;
7、返回控制權給DispatcherServlet,由DispatcherServlet返回響應給用戶,到此一個流程結束。
組件說明
以下組件通常使用框架提供實現:
u DispatcherServlet:前端控制器
用戶請求到達前端控制器,它就相當於mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它調用其它組件處理用戶的請求,dispatcherServlet的存在降低了組件之間的耦合性。
u HandlerMapping:處理器映射器
HandlerMapping負責根據用戶請求找到Handler即處理器,springmvc提供了不同的映射器實現不同的映射方式,例如:配置文件方式,實現接口方式,注解方式等。
u Handler:處理器
Handler 是繼DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進行處理。
由於Handler涉及到具體的用戶業務請求,所以一般情況需要程序員根據業務需求開發Handler。
u HandlAdapter:處理器適配器
通過HandlerAdapter對處理器進行執行,這是適配器模式的應用,通過擴展適配器可以對更多類型的處理器進行執行。
u View Resolver:視圖解析器
View Resolver負責將處理結果生成View視圖,View Resolver首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最后對View進行渲染將處理結果通過頁面展示給用戶。
u View:視圖
springmvc框架提供了很多的View視圖類型的支持,包括:jstlView、freemarkerView、pdfView等。我們最常用的視圖就是jsp。
一般情況下需要通過頁面標簽或頁面模版技術將模型數據通過頁面展示給用戶,需要由程序員根據業務需求開發具體的頁面。
注解描述:
@RequestMapping:定義請求url到處理器功能方法的映射
RequestMappingHandlerAdapter
注解式處理器適配器,對標記@ResquestMapping的方法進行適配。
從spring3.1版本開始,廢除了AnnotationMethodHandlerAdapter的使用,推薦使用RequestMappingHandlerAdapter完成注解式處理器適配。
配置如下:
<!--注解適配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:annotation-driven>
springmvc使用<mvc:annotation-driven>自動加載RequestMappingHandlerMapping和RequestMappingHandlerAdapter,可用在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解處理器和適配器的配置。
1.1 視圖解析器
在springmvc.xml文件配置如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
InternalResourceViewResolver:支持JSP視圖解析
viewClass:JstlView表示JSP模板頁面需要使用JSTL標簽庫,所以classpath中必須包含jstl的相關jar 包。此屬性可以不設置,默認為JstlView。
prefix 和suffix:查找視圖頁面的前綴和后綴,最終視圖的址為:
前綴+邏輯視圖名+后綴,邏輯視圖名需要在controller中返回ModelAndView指定,比如邏輯視圖名為hello,則最終返回的jsp視圖地址 “WEB-INF/jsp/hello.jsp”
DispatcherServlet核心代碼分析
//前端控制器分派方法 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; try { ModelAndView mv; boolean errorView = false; try { //檢查是否是請求是否是multipart(如文件上傳),如果是將通過MultipartResolver解析 processedRequest = checkMultipart(request); //步驟2、請求到處理器(頁面控制器)的映射,通過HandlerMapping進行映射 mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } //步驟3、處理器適配,即將我們的處理器包裝成相應的適配器(從而支持多種類型的處理器) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 304 Not Modified緩存支持 //此處省略具體代碼 // 執行處理器相關的攔截器的預處理(HandlerInterceptor.preHandle) //此處省略具體代碼 // 步驟4、由適配器執行處理器(調用處理器相應功能處理方法) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } // 執行處理器相關的攔截器的后處理(HandlerInterceptor.postHandle) //此處省略具體代碼 } catch (ModelAndViewDefiningException ex) { logger.debug("ModelAndViewDefiningException encountered", ex); mv = ex.getModelAndView(); } catch (Exception ex) { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(processedRequest, response, handler, ex); errorView = (mv != null); } //步驟5 步驟6、解析視圖並進行視圖的渲染 //步驟5 由ViewResolver解析View(viewResolver.resolveViewName(viewName, locale)) 步驟6 視圖在渲染時會把Model傳入(view.render(mv.getModelInternal(), request, response);) if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } // 執行處理器相關的攔截器的完成后處理(HandlerInterceptor.afterCompletion) //此處省略具體代碼 catch (Exception ex) { // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex) throw ex; } catch (Error err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } finally { // Clean up any resources used by a multipart request. if (processedRequest != request) { cleanupMultipart(processedRequest); } } }
