請求提交給DispatchServlet
html
查找HandlerMapping
java
調用由HandlerAdapter
封裝後的Handler
web
返回ModelAndView
到DispatcherServlet
spring
藉由ViewResolver
完成邏輯視圖到真實視圖的轉換json
返回響應api
web.xml
瀏覽器
<web-app> <!-- 父容器配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationServlet.xml, </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 子容器配置 --> <servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>logLevel</param-name> <param-value>FINE</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- url映射 --> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> </web-app>
子容器能夠訪問父容器的bean,父容器不能訪問子容器的bean緩存
默認採用org.springframework.web.context.ContextLoaderListener
mvc
默認使用/WEB-INF/{servlet-name}-*.xml
加載子容器app
DispatcherServlet
初始化
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
默認配置: DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
@Controller
(由Spring識別Handler
實例)
@RequestMapping(value=, method=, params=)
@RequestMapping(value=, method=, params=)
@PathVariable
,配合佔位符{parameter}
@RequestParam(value=, required=, defaultValue=)
@CookieValue(value=, required=, defaultValue=)
@RequestHeader(value=, required=, defaultValue=)
HttpServletRequest
, WebRequest
, ServletRequest
的InputStream
/ Reader
HttpServeltResponse
, ServletResponse的OutputStream
/ Writer
HttpMessageConverter<T>
使用@RequestBody
/ @ResponseBody
;使用HttpEntity<T>
/ ResponseEntity<T>
Spring根據HTTP報文頭部的Accept
指定的MIME類型,查找匹配的HttpMessageConverter
Spring MVC默認裝配AnnotationMethodHandlerAdapter
,調用HttpMessageConverter
mvc命名空間的<mvc:annotation-driven/>
標籤會建立並註冊一個默認的DefaultAnnotationHandlerMapping
和一個AnnotationMethodHandlerAdapter
實例,若是上下文中存在自定義的對應組件bean,則覆蓋默認配置
app-servlet.xml
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> <property name="alwaysUseFullPath" value="true"/> <property name="interceptors"> <list> <ref bean="monitorInterceptor"/> <ref bean="commonOutLogInterceptor"/> <ref bean="serverTraceInterceptor"/> </list> </property> </bean> <bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="writeAcceptCharset" value="false"/> </bean> <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/> <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <bean class="org.springframework.http.MediaType"> <constructor-arg value="text"/> <constructor-arg value="json"/> <constructor-arg> <map> <entry key="charset" value="UTF-8" /> </map> </constructor-arg> </bean> </list> </property> </bean> </list> </property> </bean>
Spring MVC在調用方法前會建立一個隱含的模型對象
ModelAndView
:返回值類型爲ModelAndView
時,方法體經過該對象添加模型數據
@ModelAttribute
:入參對象添加到數據模型中
Map和Model:入參爲org.springframework.ui.Model
、org.springframework.ui.ModelMap
或java.util.Map
時,處理方法返回時,Map中的數據會自動添加到模型中
@SessionAttributes
:將模型中的某個屬性暫存到HttpSession
中,以便多個請求共享
Spring MVC將ServletRequest
對象及處理方法的入參實例傳遞給DataBinder
;
DataBinder
調用ConversionService
組件進行數據類型轉換、數據格式化等工做,將ServletRequest
中的消息填充到入參對象中;
而後再調用Validator
組件對已經綁定了請求消息數據的入參對象進行數據合法性校驗,並最終生成綁定結果BindingResult
對象,其中還包含相應的校驗錯誤對象
抽取BindingResult
中的入參對象及校驗錯誤對象,賦給處理方法的相應入參
例如:將請求信息中A類型參數轉換並綁定到Controller對應的處理方法的B類型入參中
基於ConversionService
接口,Spring將自動識別其實現類,用於入參類型轉換,相似於C++中的自定義類型轉換。例如,將http請求信息中的字符串格式參數轉換爲Controller對應方法中的類類型入參
可經過ConversionServiceFactoryBean
的converters
屬性註冊自定義轉換器。可接受Converter
,ConverterFacotory
,GenericConverter
或ConditionalConverterFactory
的實現類,並統一封裝到一個ConversionService
的實例(即GenericConversionService
)中
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="MyConverters" /> </list> </property> </bean>
<mvc:annotation-driven/>
標籤還會註冊一個默認的ConversionService
,即FormattingConversionServiceFactoryBean
例如:將請求信息中字符串類型參數轉換並綁定到Controller對應的處理方法入參中的Date類型屬性中
格式化框架定義了Formatter<T>
接口,擴展於Printer<T>
和Parser<T>
接口
Srping提供AnnotationFormatterFactory<A extends Annotation>
接口及兩個實現類:NumberFormatAnnotationFormatterFactory
和JodaDateTimeFormatAnnotationFormatterFactory
在入參類屬性上使用註解:@DateTimeFormat
,@NumberFormat
Spring經過<mvc:annotation-driven/>
標籤建立FormattingConversionServiceFactoryBean
做爲FormattingConversionService
的實例,自動裝配NumberFormatAnnotationFormatterFactory
和JodaDateTimeFormatAnnotationFormatterFactory
<mvc:annotation-driven/>
標籤會默認裝配LocalValidatorFactoryBean
,實現了Spring的Validator
接口,經過在入參上標註@Valid
註解便可讓Spring在完成數據綁定後執行數據校驗
@Valid
註解標註的入參和其後的BindingResult
或Errors
入參成對出現,後者保存前者的校驗結果
校驗結果也保存在MVC的隱含模型中
樣例
public Class User { private String userId; @Pattern(regexp="w{4,30}") private String userName; @Length(min=2, max=100) private String nickName; @Past @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthday; @DecimalMin(value = "1000.00") @DecimalMax(value = "10000.00") @NumberFormat(pattern = "#,###.##") pirvate Long salary; } @RequestMapping(value = "/handle") public void handle(@Valid User uer, BindingResult bindingResult) { //do something }
視圖對象是一個bean,由視圖解析器負責實例化。
不一樣的視圖實現技術對應於不一樣的View
實現類
全部的視圖解析器都實現了ViewResolver
接口
app-servlet.xml
<!-- For multipart encoding support --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="209715200"/> </bean> <bean id="beanNameResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/> <!--VM模板文件解析 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="true" /> <property name="prefix" value="" /> <property name="suffix" value=".vm" /> <property name="contentType"> <value>text/html; charset=UTF-8</value> </property> <property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml"/> </bean> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/WEB-INF/vm/" /> <property name="velocityPropertiesMap"> <props> <prop key="input.encoding">UTF-8</prop> <prop key="output.encoding">UTF-8</prop> <prop key="velocimacro.library"></prop> <prop key="velocimacro.library.autoreload">true</prop> <prop key="directive.foreach.counter.name">loopCursor</prop> <prop key="directive.foreach.counter.initial.value">0</prop> </props> </property> </bean>
須要對項目中的圖片、html靜態資源等單獨處理
配置<mvc:default-servlet-handler>
後,會裝配一個DefaultServletHttpRequestHandler
,對靜態資源作檢查
配置<mvc:resources/>
,容許對靜態資源文件路徑做映射,並提供文件在瀏覽器端的緩存控制,例如
<mvc:resources mapping="/resources/**" location="/,classpath:/META-INF/publicResources" />
DispatcherServlet
將請求交給處理器映射(HandlerMapping
),找到對應的HandlerExecutionChain
找到對應的HandlerExecutionChain
包含若干HandlerInterceptor
,和一個Handler
HandlerInterceptor
接口:
public interface HandlerInterceptor { boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
app-servlet.xml
:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/api/**" /> <bean class="outfox.ynote.webserver.web.HttpsInterceptor" /> </mvc:interceptor> </mvc:interceptors>
Spring MVC經過HandlerExceptionResolver
處理異常
HandlerExceptionResolver
接口:
public interface HandlerExceptionResolver { ModelAndView resolveException (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex); }
Spring MVC默認裝配了DefaultHandlerExceptionResolver
Spring MVC默認註冊了AnnotationMethodHandlerExceptionResolver
,容許經過@ExceptionHandler
指定處理特定異常
web.xml
<web-app> <!-- 對各類異常和錯誤,交由ErrorController處理 --> <error-page> <error-code>404</error-code> <location>/error</location> </error-page> <error-page> <error-code>403</error-code> <location>/error</location> </error-page> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error</location> </error-page> </web-app>