先來看一下什么是 MVC 模式
MVC 是一種設(shè)計(jì)模式.
MVC 的原理圖如下:

SpringMVC 簡單介紹
SpringMVC 框架是以請求為驅(qū)動,圍繞 Servlet 設(shè)計(jì),將請求發(fā)給控制器,然后通過模型對象,分派器來展示請求結(jié)果視圖。其中核心類是 DispatcherServlet,它是一個(gè) Servlet,頂層是實(shí)現(xiàn)的Servlet接口。
SpringMVC 使用
需要在 web.xml 中配置 DispatcherServlet 。并且需要配置 Spring 監(jiān)聽器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 工作原理(重要)
簡單來說:
客戶端發(fā)送請求-> 前端控制器 DispatcherServlet 接受客戶端請求 -> 找到處理器映射 HandlerMapping 解析請求對應(yīng)的 Handler-> HandlerAdapter 會根據(jù) Handler 來調(diào)用真正的處理器開處理請求,并處理相應(yīng)的業(yè)務(wù)邏輯 -> 處理器返回一個(gè)模型視圖 ModelAndView -> 視圖解析器進(jìn)行解析 -> 返回一個(gè)視圖對象->前端控制器 DispatcherServlet 渲染數(shù)據(jù)(Moder)->將得到視圖對象返回給用戶
如下圖所示:

上圖的一個(gè)筆誤的小問題:Spring MVC 的入口函數(shù)也就是前端控制器 DispatcherServlet 的作用是接收請求,響應(yīng)結(jié)果。
流程說明(重要):
(1)客戶端(瀏覽器)發(fā)送請求,直接請求到 DispatcherServlet。
(2)DispatcherServlet 根據(jù)請求信息調(diào)用 HandlerMapping,解析請求對應(yīng)的 Handler。
(3)解析到對應(yīng)的 Handler(也就是我們平常說的 Controller 控制器)后,開始由 HandlerAdapter 適配器處理。
(4)HandlerAdapter 會根據(jù) Handler 來調(diào)用真正的處理器開處理請求,并處理相應(yīng)的業(yè)務(wù)邏輯。
(5)處理器處理完業(yè)務(wù)后,會返回一個(gè) ModelAndView 對象,Model 是返回的數(shù)據(jù)對象,View 是個(gè)邏輯上的 View。
(6)ViewResolver 會根據(jù)邏輯 View 查找實(shí)際的 View。
(7)DispaterServlet 把返回的 Model 傳給 View(視圖渲染)。
(8)把 View 返回給請求者(瀏覽器)
SpringMVC 重要組件說明
1、前端控制器DispatcherServlet(不需要工程師開發(fā)),由框架提供(重要)
作用:Spring MVC 的入口函數(shù)。接收請求,響應(yīng)結(jié)果,相當(dāng)于轉(zhuǎn)發(fā)器,中央處理器。有了 DispatcherServlet 減少了其它組件之間的耦合度。用戶請求到達(dá)前端控制器,它就相當(dāng)于mvc模式中的c,DispatcherServlet是整個(gè)流程控制的中心,由它調(diào)用其它組件處理用戶的請求,DispatcherServlet的存在降低了組件之間的耦合性。
2、處理器映射器HandlerMapping(不需要工程師開發(fā)),由框架提供
作用:根據(jù)請求的url查找Handler。HandlerMapping負(fù)責(zé)根據(jù)用戶請求找到Handler即處理器(Controller),SpringMVC提供了不同的映射器實(shí)現(xiàn)不同的映射方式,例如:配置文件方式,實(shí)現(xiàn)接口方式,注解方式等。
3、處理器適配器HandlerAdapter
作用:按照特定規(guī)則(HandlerAdapter要求的規(guī)則)去執(zhí)行Handler
通過HandlerAdapter對處理器進(jìn)行執(zhí)行,這是適配器模式的應(yīng)用,通過擴(kuò)展適配器可以對更多類型的處理器進(jìn)行執(zhí)行。
4、處理器Handler(需要工程師開發(fā))
注意:編寫Handler時(shí)按照HandlerAdapter的要求去做,這樣適配器才可以去正確執(zhí)行Handler
Handler 是繼DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進(jìn)行處理。
由于Handler涉及到具體的用戶業(yè)務(wù)請求,所以一般情況需要工程師根據(jù)業(yè)務(wù)需求開發(fā)Handler。
5、視圖解析器View resolver(不需要工程師開發(fā)),由框架提供
作用:進(jìn)行視圖解析,根據(jù)邏輯視圖名解析成真正的視圖(view)
View Resolver負(fù)責(zé)將處理結(jié)果生成View視圖,View Resolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最后對View進(jìn)行渲染將處理結(jié)果通過頁面展示給用戶。 springmvc框架提供了很多的View視圖類型,包括:jstlView、freemarkerView、pdfView等。
一般情況下需要通過頁面標(biāo)簽或頁面模版技術(shù)將模型數(shù)據(jù)通過頁面展示給用戶,需要由工程師根據(jù)業(yè)務(wù)需求開發(fā)具體的頁面。
6、視圖View(需要工程師開發(fā))
View是一個(gè)接口,實(shí)現(xiàn)類支持不同的View類型(jsp、freemarker、pdf...)
注意:處理器Handler(也就是我們平常說的Controller控制器)以及視圖層view都是需要我們自己手動開發(fā)的。其他的一些組件比如:前端控制器DispatcherServlet、處理器映射器HandlerMapping、處理器適配器HandlerAdapter等等都是框架提供給我們的,不需要自己手動開發(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映射請求和一系列的對于攔截器的前處理和后處理,大部分用@Controller注解。
- HandlerAdapter:幫助DispatcherServlet處理映射請求處理程序的適配器,而不用考慮實(shí)際調(diào)用的是 哪個(gè)處理程序。- - -
- ViewResolver:根據(jù)實(shí)際配置解析實(shí)際的View類型。
- ThemeResolver:解決Web應(yīng)用程序可以使用的主題,例如提供個(gè)性化布局。
- MultipartResolver:解析多部分請求,以支持從HTML表單上傳文件。-
- FlashMapManager:存儲并檢索可用于將一個(gè)請求屬性傳遞到另一個(gè)請求的input和output的FlashMap,通常用于重定向。
在Web MVC框架中,每個(gè)DispatcherServlet都擁自己的WebApplicationContext,它繼承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet實(shí)例之間共享的所有的基礎(chǔ)框架beans。
HandlerMapping

HandlerMapping接口處理請求的映射HandlerMapping接口的實(shí)現(xiàn)類:
- SimpleUrlHandlerMapping類通過配置文件把URL映射到Controller類。
- DefaultAnnotationHandlerMapping類通過注解把URL映射到Controller類。
HandlerAdapter

HandlerAdapter接口-處理請求映射
AnnotationMethodHandlerAdapter:通過注解,把請求URL映射到Controller類的方法上。
HandlerExceptionResolver

HandlerExceptionResolver接口-異常處理接口
- SimpleMappingExceptionResolver通過配置文件進(jìn)行異常處理。
- AnnotationMethodHandlerExceptionResolver:通過注解進(jìn)行異常處理。
ViewResolver

ViewResolver接口解析View視圖。
UrlBasedViewResolver類 通過配置文件,把一個(gè)視圖名交給到一個(gè)View來處理。