MVC 的原理圖如下:
SpringMVC 簡(jiǎn)單介紹
SpringMVC 框架是以請(qǐng)求為驅(qū)動(dòng)劝枣,圍繞 Servlet 設(shè)計(jì),將請(qǐng)求發(fā)給控制器律罢,然后通過(guò)模型對(duì)象缓待,分派器來(lái)展示請(qǐng)求結(jié)果視圖。其中核心類是 DispatcherServlet族沃,它是一個(gè) Servlet频祝,頂層是實(shí)現(xiàn)的Servlet接口。
SpringMVC 使用
需要在 web.xml 中配置 DispatcherServlet 脆淹。并且需要配置 Spring 監(jiān)聽(tīng)器ContextLoaderListener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 如果不設(shè)置init-param標(biāo)簽常空,則必須在/WEB-INF/下創(chuàng)建xxx-servlet.xml文件,其中xxx是servlet-name中配置的名稱盖溺。 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
SpringMVC 工作原理(重要)
簡(jiǎn)單來(lái)說(shuō):
客戶端發(fā)送請(qǐng)求-> 前端控制器 DispatcherServlet 接受客戶端請(qǐng)求 -> 找到處理器映射 HandlerMapping 解析請(qǐng)求對(duì)應(yīng)的 Handler-> HandlerAdapter 會(huì)根據(jù) Handler 來(lái)調(diào)用真正的處理器開(kāi)處理請(qǐng)求漓糙,并處理相應(yīng)的業(yè)務(wù)邏輯 -> 處理器返回一個(gè)模型視圖 ModelAndView -> 視圖解析器進(jìn)行解析 -> 返回一個(gè)視圖對(duì)象->前端控制器 DispatcherServlet 渲染數(shù)據(jù)(Moder)->將得到視圖對(duì)象返回給用戶
如下圖所示:
上圖的一個(gè)筆誤的小問(wèn)題:Spring MVC 的入口函數(shù)也就是前端控制器 DispatcherServlet 的作用是接收請(qǐng)求,響應(yīng)結(jié)果烘嘱。
流程說(shuō)明(重要):
(1)客戶端(瀏覽器)發(fā)送請(qǐng)求昆禽,直接請(qǐng)求到 DispatcherServlet。
(2)DispatcherServlet 根據(jù)請(qǐng)求信息調(diào)用 HandlerMapping蝇庭,解析請(qǐng)求對(duì)應(yīng)的 Handler醉鳖。
(3)解析到對(duì)應(yīng)的 Handler(也就是我們平常說(shuō)的 Controller 控制器)后,開(kāi)始由 HandlerAdapter 適配器處理哮内。
(4)HandlerAdapter 會(huì)根據(jù) Handler 來(lái)調(diào)用真正的處理器開(kāi)處理請(qǐng)求盗棵,并處理相應(yīng)的業(yè)務(wù)邏輯。
(5)處理器處理完業(yè)務(wù)后牍蜂,會(huì)返回一個(gè) ModelAndView 對(duì)象漾根,Model 是返回的數(shù)據(jù)對(duì)象,View 是個(gè)邏輯上的 View鲫竞。
(6)ViewResolver 會(huì)根據(jù)邏輯 View 查找實(shí)際的 View辐怕。
(7)DispaterServlet 把返回的 Model 傳給 View(視圖渲染)。
(8)把 View 返回給請(qǐng)求者(瀏覽器)
SpringMVC 重要組件說(shuō)明
1从绘、前端控制器DispatcherServlet(不需要工程師開(kāi)發(fā)),由框架提供(重要)
作用:Spring MVC 的入口函數(shù)寄疏。接收請(qǐng)求是牢,響應(yīng)結(jié)果,相當(dāng)于轉(zhuǎn)發(fā)器陕截,中央處理器驳棱。有了 DispatcherServlet 減少了其它組件之間的耦合度。用戶請(qǐng)求到達(dá)前端控制器农曲,它就相當(dāng)于mvc模式中的c社搅,DispatcherServlet是整個(gè)流程控制的中心,由它調(diào)用其它組件處理用戶的請(qǐng)求乳规,DispatcherServlet的存在降低了組件之間的耦合性形葬。
2、處理器映射器HandlerMapping(不需要工程師開(kāi)發(fā)),由框架提供
作用:根據(jù)請(qǐng)求的url查找Handler暮的。HandlerMapping負(fù)責(zé)根據(jù)用戶請(qǐng)求找到Handler即處理器(Controller)笙以,SpringMVC提供了不同的映射器實(shí)現(xiàn)不同的映射方式,例如:配置文件方式冻辩,實(shí)現(xiàn)接口方式猖腕,注解方式等。
3恨闪、處理器適配器HandlerAdapter
作用:按照特定規(guī)則(HandlerAdapter要求的規(guī)則)去執(zhí)行Handler
通過(guò)HandlerAdapter對(duì)處理器進(jìn)行執(zhí)行倘感,這是適配器模式的應(yīng)用,通過(guò)擴(kuò)展適配器可以對(duì)更多類型的處理器進(jìn)行執(zhí)行凛剥。
4侠仇、處理器Handler(需要工程師開(kāi)發(fā))
注意:編寫(xiě)Handler時(shí)按照HandlerAdapter的要求去做,這樣適配器才可以去正確執(zhí)行Handler
Handler 是繼DispatcherServlet前端控制器的后端控制器犁珠,在DispatcherServlet的控制下Handler對(duì)具體的用戶請(qǐng)求進(jìn)行處理逻炊。
由于Handler涉及到具體的用戶業(yè)務(wù)請(qǐng)求,所以一般情況需要工程師根據(jù)業(yè)務(wù)需求開(kāi)發(fā)Handler犁享。
5余素、視圖解析器View resolver(不需要工程師開(kāi)發(fā)),由框架提供
作用:進(jìn)行視圖解析,根據(jù)邏輯視圖名解析成真正的視圖(view)
View Resolver負(fù)責(zé)將處理結(jié)果生成View視圖炊昆,View Resolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁(yè)面地址桨吊,再生成View視圖對(duì)象,最后對(duì)View進(jìn)行渲染將處理結(jié)果通過(guò)頁(yè)面展示給用戶凤巨。 springmvc框架提供了很多的View視圖類型视乐,包括:jstlView、freemarkerView敢茁、pdfView等佑淀。
一般情況下需要通過(guò)頁(yè)面標(biāo)簽或頁(yè)面模版技術(shù)將模型數(shù)據(jù)通過(guò)頁(yè)面展示給用戶,需要由工程師根據(jù)業(yè)務(wù)需求開(kāi)發(fā)具體的頁(yè)面彰檬。
6伸刃、視圖View(需要工程師開(kāi)發(fā))
View是一個(gè)接口谎砾,實(shí)現(xiàn)類支持不同的View類型(jsp、freemarker捧颅、pdf…)
注意:處理器Handler(也就是我們平常說(shuō)的Controller控制器)以及視圖層view都是需要我們自己手動(dòng)開(kāi)發(fā)的景图。其他的一些組件比如:前端控制器DispatcherServlet、處理器映射器HandlerMapping碉哑、處理器適配器HandlerAdapter等等都是框架提供給我們的挚币,不需要自己手動(dòng)開(kāi)發(fā)。
DispatcherServlet詳細(xì)解析
首先看下源碼:
package org.springframework.web.servlet;
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
private static final Properties defaultStrategies;
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
private boolean detectAllHandlerAdapters = true;
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
private boolean detectAllHandlerExceptionResolvers = true;
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
private boolean detectAllViewResolvers = true;
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
/** Perform cleanup of request attributes after include request? */
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
public DispatcherServlet() {
super();
}
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
DispatcherServlet類中的屬性beans:
HandlerMapping:用于handlers映射請(qǐng)求和一系列的對(duì)于攔截器的前處理和后處理谭梗,大部分用@Controller注解忘晤。
HandlerAdapter:幫助DispatcherServlet處理映射請(qǐng)求處理程序的適配器宛蚓,而不用考慮實(shí)際調(diào)用的是 哪個(gè)處理程序激捏。- - -
ViewResolver:根據(jù)實(shí)際配置解析實(shí)際的View類型。
ThemeResolver:解決Web應(yīng)用程序可以使用的主題凄吏,例如提供個(gè)性化布局远舅。
MultipartResolver:解析多部分請(qǐng)求,以支持從HTML表單上傳文件痕钢。-
FlashMapManager:存儲(chǔ)并檢索可用于將一個(gè)請(qǐng)求屬性傳遞到另一個(gè)請(qǐng)求的input和output的FlashMap图柏,通常用于重定向。
在Web MVC框架中任连,每個(gè)DispatcherServlet都擁自己WebApplicationContext蚤吹,它繼承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet實(shí)例之間共享的所有的基礎(chǔ)框架beans随抠。
HandlerMapping
HandlerMapping接口處理請(qǐng)求的映射HandlerMapping接口的實(shí)現(xiàn)類:
SimpleUrlHandlerMapping類通過(guò)配置文件把URL映射到Controller類裁着。
DefaultAnnotationHandlerMapping類通過(guò)注解把URL映射到Controller類。
HandlerAdapter
HandlerAdapter接口-處理請(qǐng)求映射
AnnotationMethodHandlerAdapter:通過(guò)注解拱她,把請(qǐng)求URL映射到Controller類的方法上二驰。
HandlerExceptionResolver
HandlerExceptionResolver接口-異常處理接口
SimpleMappingExceptionResolver通過(guò)配置文件進(jìn)行異常處理。
AnnotationMethodHandlerExceptionResolver:通過(guò)注解進(jìn)行異常處理秉沼。
ViewResolver接口解析View視圖桶雀。
UrlBasedViewResolver類 通過(guò)配置文件,把一個(gè)視圖名交給到一個(gè)View來(lái)處理唬复。