Learn Spring - Spring MVC

1. 處理流程

  • 請求提交給DispatchServlethtml

  • 查找HandlerMappingjava

  • 調用由HandlerAdapter封裝後的Handlerweb

  • 返回ModelAndViewDispatcherServletspring

  • 藉由ViewResolver完成邏輯視圖到真實視圖的轉換json

  • 返回響應api

2. 配置DispatcherServlet

  • 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.ContextLoaderListenermvc

  • 默認使用/WEB-INF/{servlet-name}-*.xml加載子容器app

3. DispatcherServlet的初始化

  • 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

4. Controller註解

4.1 類註解

  • @Controller(由Spring識別Handler實例)

  • @RequestMapping(value=, method=, params=)

4.2 方法註解

  • @RequestMapping(value=, method=, params=)

  • @PathVariable,配合佔位符{parameter}

  • @RequestParam(value=, required=, defaultValue=)

  • @CookieValue(value=, required=, defaultValue=)

  • @RequestHeader(value=, required=, defaultValue=)

5. 封裝入參

  • HttpServletRequest, WebRequest, ServletRequestInputStream / Reader

  • HttpServeltResponse, ServletResponse的OutputStream / Writer

6. 請求信息和對象的轉換

6.1 基本

  • HttpMessageConverter<T>

  • 使用@RequestBody / @ResponseBody;使用HttpEntity<T> / ResponseEntity<T>

  • Spring根據HTTP報文頭部的Accept指定的MIME類型,查找匹配的HttpMessageConverter

  • Spring MVC默認裝配AnnotationMethodHandlerAdapter,調用HttpMessageConverter

  • mvc命名空間的<mvc:annotation-driven/>標籤會建立並註冊一個默認的DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例,若是上下文中存在自定義的對應組件bean,則覆蓋默認配置

6.2 樣例

  • 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>

7. 處理模型數據

  • Spring MVC在調用方法前會建立一個隱含的模型對象

  • ModelAndView:返回值類型爲ModelAndView時,方法體經過該對象添加模型數據

  • @ModelAttribute:入參對象添加到數據模型中

  • Map和Model:入參爲org.springframework.ui.Modelorg.springframework.ui.ModelMapjava.util.Map時,處理方法返回時,Map中的數據會自動添加到模型中

  • @SessionAttributes:將模型中的某個屬性暫存到HttpSession中,以便多個請求共享

8. 數據綁定

8.1 基本

  • Spring MVC將ServletRequest對象及處理方法的入參實例傳遞給DataBinder

  • DataBinder調用ConversionService組件進行數據類型轉換、數據格式化等工做,將ServletRequest中的消息填充到入參對象中;

  • 而後再調用Validator組件對已經綁定了請求消息數據的入參對象進行數據合法性校驗,並最終生成綁定結果BindingResult對象,其中還包含相應的校驗錯誤對象

  • 抽取BindingResult中的入參對象及校驗錯誤對象,賦給處理方法的相應入參

8.2 數據轉換

  • 例如:將請求信息中A類型參數轉換並綁定到Controller對應的處理方法的B類型入參中

  • 基於ConversionService接口,Spring將自動識別其實現類,用於入參類型轉換,相似於C++中的自定義類型轉換。例如,將http請求信息中的字符串格式參數轉換爲Controller對應方法中的類類型入參

  • 可經過ConversionServiceFactoryBeanconverters屬性註冊自定義轉換器。可接受ConverterConverterFacotoryGenericConverterConditionalConverterFactory的實現類,並統一封裝到一個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

8.3 數據格式化

  • 例如:將請求信息中字符串類型參數轉換並綁定到Controller對應的處理方法入參中的Date類型屬性中

  • 格式化框架定義了Formatter<T>接口,擴展於Printer<T>Parser<T>接口

  • Srping提供AnnotationFormatterFactory<A extends Annotation>接口及兩個實現類:NumberFormatAnnotationFormatterFactoryJodaDateTimeFormatAnnotationFormatterFactory

  • 在入參類屬性上使用註解:@DateTimeFormat@NumberFormat

  • Spring經過<mvc:annotation-driven/>標籤建立FormattingConversionServiceFactoryBean做爲FormattingConversionService的實例,自動裝配NumberFormatAnnotationFormatterFactoryJodaDateTimeFormatAnnotationFormatterFactory

8.4 數據驗證

  • <mvc:annotation-driven/>標籤會默認裝配LocalValidatorFactoryBean,實現了Spring的Validator接口,經過在入參上標註@Valid註解便可讓Spring在完成數據綁定後執行數據校驗

  • @Valid註解標註的入參和其後的BindingResultErrors入參成對出現,後者保存前者的校驗結果

  • 校驗結果也保存在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
}

9. 視圖解析

9.1 基本

  • 視圖對象是一個bean,由視圖解析器負責實例化。

  • 不一樣的視圖實現技術對應於不一樣的View實現類

  • 全部的視圖解析器都實現了ViewResolver接口

9.2 樣例

  • 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>

10. 靜態資源處理

  • 須要對項目中的圖片、html靜態資源等單獨處理

  • 配置<mvc:default-servlet-handler>後,會裝配一個DefaultServletHttpRequestHandler,對靜態資源作檢查

  • 配置<mvc:resources/>,容許對靜態資源文件路徑做映射,並提供文件在瀏覽器端的緩存控制,例如

<mvc:resources mapping="/resources/**" location="/,classpath:/META-INF/publicResources" />

11. 攔截器

11.1 基本

  • 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;
}

11.2 樣例

  • app-servlet.xml:

<mvc:interceptors>
    <mvc:interceptor>
      <mvc:mapping path="/api/**" />
      <bean class="outfox.ynote.webserver.web.HttpsInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

12. 異常處理

12.1 基本

  • Spring MVC經過HandlerExceptionResolver處理異常

  • HandlerExceptionResolver接口:

public interface HandlerExceptionResolver {
  ModelAndView resolveException (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
  • Spring MVC默認裝配了DefaultHandlerExceptionResolver

  • Spring MVC默認註冊了AnnotationMethodHandlerExceptionResolver,容許經過@ExceptionHandler指定處理特定異常

12.2 樣例

  • 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>
相關文章
相關標籤/搜索