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

  • 相关阅读:
    【Hadoop】MapReduce练习:多job关联实现倒排索引
    【Hadoop】MapReduce练习:分科目等级并按分区统计学生以及人数
    【Zookeeper】利用zookeeper搭建Hdoop HA高可用
    【Linux】部署NTP时间同步服务器
    VSCode前端文件以服务器模式打开
    移动端公共方法封装
    常用浏览器及内核
    XHTML和HTML的区别
    javascript算法
    计算属性和侦听器
  • 原文地址:https://www.cnblogs.com/lzfhope/p/16103174.html
Copyright © 2020-2023  润新知