Spring之WebMvcConfigurationSupport


      WebMvcConfigurationSupport是mvc的核心配置。開發spring,了解和掌握這個是必須的。

     為了簡約篇幅,本文把"WebMvcConfigurationSupport"縮寫為wms。

     本文主要關注圍繞DispatcherServlet(分發者服務程序)發生的和wms有關的一些內容,不關注http請求在容器部分的機制和代碼。

     通過本文能夠:

  1. 了解wms是做什么的
  2. 了解大體如何使用wms
  3. 作為了解和使用wms的一個簡單參考

一、wms的介紹

1.原文注釋

    This is the main class providing the configuration behind the MVC Java config.
    It is typically imported by adding @EnableWebMvc to anapplication @Configuration class.
    An alternative more advanced option is to extend directly from this class and override methods as necessary,
    remembering to add @Configuration to the subclass and @Bean to overridden @Bean methods.
    For more details see the javadoc of @EnableWebMvc.

This class registers the following HandlerMappings:
    •RequestMappingHandlerMapping ordered at 0 for mapping requests to annotated controller methods.
    •HandlerMapping ordered at 1 to map URL paths directly to view names.
    •BeanNameUrlHandlerMapping ordered at 2 to map URL paths to controller bean names.
    •RouterFunctionMapping  ordered at 3 to map router functions.
    •HandlerMapping ordered at Integer.MAX_VALUE-1 to serve static resource requests.
    •HandlerMapping ordered at Integer.MAX_VALUE to forward requests to the default servlet.

Registers these HandlerAdapters:
    •RequestMappingHandlerAdapter for processing requests with annotated controller methods.
    •HttpRequestHandlerAdapter for processing requests with HttpRequestHandlers.
    •SimpleControllerHandlerAdapter for processing requests with interface-based Controllers.
    •HandlerFunctionAdapter for processing requests with router functions.

Registers a HandlerExceptionResolverComposite with this chain ofexception resolvers:
    •ExceptionHandlerExceptionResolver for handling exceptions through org.springframework.web.bind.annotation.ExceptionHandler methods.
    •ResponseStatusExceptionResolver for exceptions annotated with org.springframework.web.bind.annotation.ResponseStatus.
    •DefaultHandlerExceptionResolver for resolving known Springexception types

Registers an AntPathMatcher and a UrlPathHelperto be used by:
    •the RequestMappingHandlerMapping,
    •the HandlerMapping for ViewControllers
    •and the HandlerMapping for serving resources
    Note that those beans can be configured with a PathMatchConfigurer.

Both the RequestMappingHandlerAdapter and the ExceptionHandlerExceptionResolver are configured with default instances of the following by default:
    •a ContentNegotiationManager
    •a Default FormattingConversionService
    •an org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean if a JSR-303 implementation is available on the classpath
    •a range of HttpMessageConverters depending on the third-partylibraries available on the classpath.

  我們翻譯下:

    wms是webMvc通過java代碼方式配置的主類。
    典型地,可以通過給一個應用的配置類(帶@Configuration)添加@EnableWebMvc注解,即可導入Mvc java 配置。
    另外一個更加高級的替代選項是繼承本類,並根據需要重寫一些方法,並記得為這個子類添加@Configuration注解,同時為那些重寫@Bean方法添加@Bean注解。
    更多的內容,請參考@EnableWebMvc的java文檔

    本類注冊以下處理器映射:
    .RequestMappingHandlerMapping(RequestMapping處理器映射) ,順序為0,用於映射帶注解的控制器方法
    .HandlerMapping (處理器映射),順序1,用於映射url路徑和視圖名稱
    .BeanNameUrlHandlerMapping(bean名稱處理器映射),順序2,用於映射url路徑到控制器bean名稱
    .RouterFunctionMapping(路由器功能映射),順序3,用於映射路由函數
    .HandlerMapping (處理器映射),順序Integer.MAX_VALUE-1,用於處理靜態資源請求
    .HandlerMapping (處理器映射),順序Integer.MAX_VALUE,用於服務器內部重定向到一個默認的servlet


    注冊這些處理器適配器:
    •RequestMappingHandlerAdapter(RequestMapping處理器適配器),用於處理到帶注解的控制器方法請求
    •HttpRequestHandlerAdapter(http請求處理器適配器),用於處理 帶HttpRequestHanders的請求
    •SimpleControllerHandlerAdapter(簡單控制器處理器適配器),用於處理基於接口的控制的請求
    •HandlerFunctionAdapter(處理器功能適配器),用於處理帶路由器功能的請求


    注冊處理器異常解析復合器,該復合器帶有一些異常處理器:    
    •ExceptionHandlerExceptionResolver(異常處理器異常解析器),用於處理org.springframework.web.bind.annotation.ExceptionHandler的異常
    •ResponseStatusExceptionResolver(響應狀態異常解析器),用於處理org.springframework.web.bind.annotation.ResponseStatus異常
    •DefaultHandlerExceptionResolver(默認處理器異常解析器),用於處理已知的的spring異常類


    注冊一個antPathMatcher和一個urlPathHelper,以便能夠被以下對象使用:
    •RequestMappingHandlerMapping(RequestMapping處理器映射)
    •HandlerMapping for ViewControllers ,用於視圖控制器的處理器映射
    •HandlerMapping for serving resources ,用於處理資源的處理器映射
    注意,以上這些bean可以通過PathMatchCOnfigurer配置。


    RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver都由以下對象的默認實例配置了:
    .ContentNegotiationManager(媒體類型管理器,用於偵測請求的媒體類型)
    .FormattingConversionService(格式轉換服務)
    .org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean(bean驗證器,如果類路徑具有JSR-303的實現)
    .HttpMessageConverters(http消息轉換器)。具體有幾個轉換器,需要看類路徑的三方實現庫的多寡

  

2.功能

     如它的名稱,即執行各種webMvc的配置,通過在其中定義大量的有關Bean(大約有25個左右),方便MVC的流程的特定環節從Bean工廠中獲取這些bean,並利用這些Bean完成webMvc的大部分工作。

     概括下,wms就是這些功能:

  • 注冊處理器映射,以便把請求導向具體的控制器、控制器方法、視圖、資源。注意,這些映射器的目的是做一個關系匹配
  • 注冊處理器適配器,為具體的功能選擇具體的處理程序。例如參數解析,消息轉換等
  • 注冊異常處理器
  • 注冊路徑映射解析有關類

      總而言之,言而總之,wms就是告訴spring用於處理請求的有關工具,這些工具用於處理映射關系,解析參數,返回消息等等

      一個完整的web請求和響應過程中需要執行的動作所使用的配置(程序、配置)基本都可以在wms中進行管理,記住這一點基本上算是對wms有所了解了

二、名詞解析

需要記住和理解的名詞非常多,只能挑本人關注的。

1.解釋器/解決器

英文:Resolver

中文含義:問題解決者。  針對不同的場景,可以有很多的解釋。在本文中,按照習慣,我們從用途進行翻譯,大體翻譯為解釋器,轉換器都可以。

2.攔截器

英文:interceptor

中文含義:進行攔截的人/物。在spring中,專門指攔截http請求的一段程序。和過濾器基本一樣,沒有什么本質上的區別。不過攔截器可以打斷請求的過程,而過濾器主要做重定向(如果有必要)

3.控制器、參數、方法

      控制器:controller,對應注解@Controller

      參數:parameter,這里主要闡述的是控制器中方法的入參

      方法:method,這里指控制器中的方法(有Request的方法)

      我們日常spring編程主要針對這三者。

      某種程度上,只要會復制粘貼+mvc你就可以說自己是一個java開發工程師了,是不是很容易啊?

4.返回值、消息

     返回值:return value。控制器方法大部分情況下都有返回值,如果沒有,那么spring也會給一個默認的響應

     消息:message.這里指從客戶端發送的請求消息或者是服務端返回給客戶端的消息。這里我們主要關心ResponseBody注解。

5.Cors

     英文:CORS(Cross-origin resource sharing)

     中文:跨源資源共享

     一般情況下,web服務器不允許跨源資源共享,但很多時候又有這個需求。所以需要指定什么資源可以被什么其它非同源請求訪問。

6.資源和視圖

     資源:resource,spring通常指靜態的數據(包括圖片,腳本,文本,多媒體信息等等)

     視圖:view,spring指展示信息的頁面

7.驗證器

     英文:validator,spring通常指用於校驗特定參數的簡單業務邏輯

8.格式化器和轉換器

     格式化器:formatter

     轉換器:converter

     二者有相通之處,但基本一致,格式和轉換基本即使你中有我,我中有你,密不可分。其作用,顧名思義,就是進行轉化/格式化。 例如消息轉換、屬性轉換等。

9.異常

   具體略。

10.應用上下文和sevlet上下文

   這兩個太重要,因為WebMvcConfigurationSupport實現的很大一部分和應用上下文、服務器上下文有關。

  • ApplicationContext:應用上下文,屬於spring自有的一個應用上下文,主要管理spring的bean。能夠管理bean,絕對是spring的最核心能力之一。

        包路徑:org.springframework.context.ApplicationContext

  • ServletContext:服務器上下文,准確地說,通常地說,它指的是web服務器/容器的根上下文,容器通常為每個應用創建一個服務器上下文,保存應用和web相關的許多基本信息。

        包路徑:javax.servlet.ServletContext

   我們開發的系統,某個方便面來說就是和兩個東西關聯:web+bean。web和bean有關的上下文就是 ServletContext,ApplicationContext。

11.媒體/媒介類型

    英文:MediaType

    包路徑:org.springframework.http.MediaType

    根據介紹,媒體/媒介類型實為MimeType的子類,spring僅僅對它做了一些包裝,方便使用。

    所以,根本上要理解MiME在http協議中的地位。

    Mime的非常友好的介紹見這里:MIME 類型 - HTTP | MDN (mozilla.org)

    或者看這里 MIME(多用途互聯網郵件擴展類型)_百度百科 (baidu.com)

    兩個結合起來,就能夠明白mime是什么東西。

    如果有什么值得記的,就是為什么叫” mail extensions"(郵件擴展)。

    郵件大概是互聯網最早傳遞的數據信息,而且基本上是最重要的,所以開始命名的時候就這么叫了。但是現在iana(互聯網號碼分配機構)又慢慢要拋棄mime這個概念,改為mediaType(媒體類型)

    很明顯這么稱呼是更加合理的,如果沒有什么特別說明,“媒體類型”就是表示MINE或者上下文類型(context-type)

 12.請求映射處理器映射器(RequestMappingHandlerMapping)

    注意這個前綴 RequestMapping(請求映射)本身是注解的名稱(@RequestMapping)。

    所以這個東西可以理解為RequestMapping注解的處理器映射器,大體作用是在注解和資源之間建立映射關系。

    我們看下源碼(默認的):

@Bean
    @SuppressWarnings("deprecation")
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
        mapping.setContentNegotiationManager(contentNegotiationManager);
        mapping.setCorsConfigurations(getCorsConfigurations());

        PathMatchConfigurer pathConfig = getPathMatchConfigurer();
        if (pathConfig.getPatternParser() != null) {
            mapping.setPatternParser(pathConfig.getPatternParser());
        }
        else {
            mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
            mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());

            Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
            if (useSuffixPatternMatch != null) {
                mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
            }
            Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
            if (useRegisteredSuffixPatternMatch != null) {
                mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
            }
        }
        Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }
        if (pathConfig.getPathPrefixes() != null) {
            mapping.setPathPrefixes(pathConfig.getPathPrefixes());
        }

        return mapping;
    }

 

   這個代碼核心是創建一個RequestMapping的處理器映射器,這個映射器又包含了什么東西了?

  1. 添加默認的轉換器和資源url管理器的攔截器
  2. 添加請求媒體類型管理器
  3. 添加了跨域請求配置
  4. 添加了路徑匹配器,以及路徑有關的一些其它程序

13.請求映射處理器適配器(RequestMappingHandlerAdapter)

     RequestMapping注解處理器適配器。

     看源碼(默認):

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
            @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") FormattingConversionService conversionService,
            @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    adapter.setContentNegotiationManager(contentNegotiationManager);
    adapter.setMessageConverters(getMessageConverters());
    adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
    adapter.setCustomArgumentResolvers(getArgumentResolvers());
    adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

    if (jackson2Present) {
        adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
        adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
    }

    AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();
    if (configurer.getTaskExecutor() != null) {
        adapter.setTaskExecutor(configurer.getTaskExecutor());
    }
    if (configurer.getTimeout() != null) {
        adapter.setAsyncRequestTimeout(configurer.getTimeout());
    }
    adapter.setCallableInterceptors(configurer.getCallableInterceptors());
    adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

    return adapter;
}
  1. 設置媒體類型管理器(和映射器一樣,都必須了解請求的媒體類型)
  2. 設置消息轉換器
  3. web綁定初始化器(和轉換服務、驗證器有關)
  4. 設置自定義參數解釋器
  5. 設置自定義返回值處理器
  6. 添加jackson請求體RequestBody顧問(如果有jackson類)
  7. 添加jackson響應體ResponseBody顧問(如果有jackson類)
  8. 配置異步任務執行器,設置異步請求超時。如果有配置異步
  9. 配置異步的可調用攔截器
  10. 配置異步延時結果攔截器

       把這個內容和RequestMappingHanlderMapping的內容對照下,我們就更能夠理解二者的區別。

       --------------------------------------------------------------------------------------------------------------------

  • 映射器:主管資源和路徑有關的內容
  • 適配器:主管具體請求消息處理返回消息

       注:spring已經提供了消息處理器的默認實現JackSon.

        RequestMappingHandlerAdapter和RequestMappingHandleMapping是DispatcherServlet(分發器)的主要處理內容。

        以下是分發器屬性的主要內容:

      

/** MultipartResolver used by this servlet. */
    @Nullable
    private MultipartResolver multipartResolver;

    /** LocaleResolver used by this servlet. */
    @Nullable
    private LocaleResolver localeResolver;

    /** ThemeResolver used by this servlet. */
    @Nullable
    private ThemeResolver themeResolver;

    /** List of HandlerMappings used by this servlet. */
    @Nullable
    private List<HandlerMapping> handlerMappings;

    /** List of HandlerAdapters used by this servlet. */
    @Nullable
    private List<HandlerAdapter> handlerAdapters;

    /** List of HandlerExceptionResolvers used by this servlet. */
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    /** RequestToViewNameTranslator used by this servlet. */
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;

    /** FlashMapManager used by this servlet. */
    @Nullable
    private FlashMapManager flashMapManager;

    /** List of ViewResolvers used by this servlet. */
    @Nullable
    private List<ViewResolver> viewResolvers;

 

三、spring-mvc種http請求大概執行過程

    這么多名詞,其實本質上就是圍繞http展開的,具體來說就是圍繞spring的http實現來展開。

    我們使用spring的主要目的就是為了web(http)應用。可以說,沒有web,spring的存在的意義基本上就沒有了。

    利用ide提供的調試工具,最容易能夠直觀地了解一個http請求的大概執行過程。如果願意,還可以詳細到每一行代碼。

    下圖是調試的時候,顯示的調用鏈:

   


四、常用-配置攔截器

     如何配置攔截器,這個沒有什么太多可說。

     記住一點,現在不但spring自身實現功能的時候使用了很多的攔截器(這個在springCloud中很明顯),就是一般的開發人員也喜歡()用大量的攔截器。

     我們只能感激一點:現在電腦越來愉快了。

     配置例子。

@Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 以下是啟用 token認證的. 本例使用cookie認證的時候,請注釋掉,避免無法完成測試
        // 反過來,如果啟用了token認證,那么過濾器驗證就可以取消掉 ,或者取消 上文的 registrationBean()
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("*.js")
                .excludePathPatterns("*.html").excludePathPatterns("*.css").excludePathPatterns("/login")
                .excludePathPatterns("/logout").excludePathPatterns("/index").excludePathPatterns("/");
        super.addInterceptors(registry);
    }

 

五、常用-方法參數(輸入)解析(請求)

    spring已經有提供默認的以下幾個注解的處理:@RequstBody,@RequestParam

    但是當我們開發api的時候,常常有這樣的需求:

  • 在過濾器或者攔截器攔截請求並獲取有關參數
  • 在具體的控制方法中想獲取請求的一些固定信息,例如登錄用戶信息,授權信息等等 。

     5.1 例子-自定義參數注解

、 如果每個地方都寫,有點麻煩,所以spring允許自定義的參數解析。

    例子:

a.定義一個注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface SessionAtrrAnnotation {

}
b.繼承並實現HandlerMethodArgumentResolver
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(SessionAtrrAnnotation.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return webRequest.getNativeRequest(HttpServletRequest.class).getSession().getAttribute("userInfo"); } }
c.在wms中注冊 @Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new LoginUserArgumentResolver()); } d.應用 @RequestMapping(value = "/deleteById") @ResponseBody public PublicReturn deleteById(@SessionAtrrAnnotation LoginUserInfo loginInfo) { //TODO:刪除用戶 return null; }

 

    5.2 自定義特定數據類型解析

    這種自定義類型,有兩種情況:

    a.解析非JSON媒體類型的參數

    b.解析媒體類型為JSON的參數中某個屬性

    這個網絡上有很多解決方案,例如:

    SpringMVC自定義處理多種日期格式的格式轉換器_二木成林的博客-CSDN博客_springmvc日期轉換   -- 這個是解析非json媒體類型參數的

    不過作者是比較傳統的xml配置,如果是springboot,直接在wms中覆蓋addFormatters即可。

    fastjson序列化時間自定義格式_biangabiang的博客-CSDN博客_fastjson自定義序列化格式 --使用阿里巴巴的fastjson,不過記得先配置Http消息轉換器為FastJson(覆蓋wms中的configureMessageConverters)

     這是因為fastjson允許針對不同類型使用不同的序列化程序。

   5.3媒體類型為JSON,且使用JackSon處理特定類型

    無論是JackSon還是FastJson的,它們都是實現了HttpMessageConverter接口。 標准一樣,細節有所區別而已。

    所以,如果使用默認的JackSon的時候,可以和網上常常提到的FASTjson一樣的思路來解決問題。

    有關內容可以看這個:Jackson Tutorial | Baeldung

    然而比較簡單的方式還是覆蓋下configureMessageConverters,在其中定制化MappingJackson2HttpMessageConverter的各種屬性。

    例如網上有這樣的例子:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
      .serializationInclusion(JsonInclude.Include.NON_NULL);
    return new MappingJackson2HttpMessageConverter(builder.build());
}

 

   如果僅僅是想自定義序列化或者反序列化器,那么使用注解即可:

@JsonSerialize(using = FamilyJSONSerializer.class)
public class Family {
    private Integer id;
    private String name;
    private Date addTime;
    private Date lastOptime;
    private String batchNo;
}

 FamilyJSONSerializer的代碼如下:

package study.config.message;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import study.model.family.Family;

public class FamilyJSONSerializer  extends JsonSerializer<Family>{

    @Override
    public void serialize(Family value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value==null) {
            gen.writeString("{}");
            return;
        }
        gen.writeString(value.toString());
    }

    @Override
    public Class<Family> handledType(){
        return Family.class;
    }
}

 

     自定義消息的解析,通常不是那么迫切,只要知道大概即可。

     沒有必要耗費太多的時間研究,並重新做一個輪子。

 

六、常用-響應消息(http消息轉換)配置(響應)

     spring的設計是允許有多個http消息轉換器,每個轉換器對應不同的媒體類型。這些轉換器只要實現HttpMessageConverter接口即可。

     當然如果你自己自定義,也可以讓一個轉換器對應n種媒體類型,或者n個轉換器對應一個媒體類型。

     如果是這種情況,spring會采用一定的選擇缺略,保證每個媒體類型都可以進行適當的轉換。

     網上太多了,不再詳細說明了。常見的即使用fastJson--覆蓋wms中的configureMessageConverters。

     下面是jackson的例子:

@Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new StringHttpMessageConverter());
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new ResourceRegionHttpMessageConverter());
        MappingJackson2HttpMessageConverter jconverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper=jconverter.getObjectMapper();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(dateFormat);
        converters.add(jconverter);
    }

   主要兩點:設置日期格式、null輸出為"",節約前端編碼工作量。

七、常用-配置視圖和資源解釋

    例如:

   @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/")
                .addResourceLocations("classpath:/public/")
                .addResourceLocations("classpath:/resources/")
                .addResourceLocations("file:" + uploadPath);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("main/index");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }

 

八、小結

     對於大部分的javaEE開發的工程師而言,都有必要理解webMvc的機制,以及wms的配置。

     wms既簡單又復雜,涉及到webMvc的方法面面,相關的源碼非常之多,如要透徹了解其原理和機制只有一個方法:仔細閱讀並做好筆記。

     此外,建議在閱讀本代碼前,先掌握http請求的基本原理和流程。另外為了提高閱讀和理解的效率,建議開啟調試模式,逐步調試,就能夠較快了解這里所涉及的有關知識。

     我個人一直喜歡用這個方法。現在ide對於這個的支持非常好,無論是eclipse,idea還是netbean,似乎除了跟蹤不到機器指令,任何東西都可以跟蹤和窺探,強大到難以置信。

     在調試過程中,可以發現代碼是從web容器(或者服務器)開始執行的,並最好從org.springframework.web.servlet.DispatcherServlet開始,因為在此類之前的大部分屬於容器的api。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM