• 第三节:<mvc:annotationdriven />标签解析


    一、<mvc:annotation-driven />配置在什么时候必须配置?

      1、配置了视图映射 view-controller

        直接配置响应的页面:无需经过控制器来执行结果 ;但会导致其他请求路径失效,需要配置mvc:annotation-driven标签

    <mvc:view-controller  path="/success" view-name="success"/>  
    

      

      2、配置了静态资源

        RESTful-CRUD操作,删除时,通过jQuery执行delete请求时,找不到静态资源,需要配置mvc:annotation-driven标签

        < mvc:default-servlet-handler /> 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理。

      3、配置了类型转换器

        配置类型转换器服务时,需要指定转换器服务引用

    <mvc:annotation-driven conversion-service=“conversionService”/> 
    会将自定义的ConversionService 注册到 Spring MVC 的上下文中
    

      

      4、完成 JSR 303 数据验证,也需要配置

    二、关于 <mvc:annotation-driven /> 作用

      1、<mvc:annotation-driven /> 会自动注册下面的组件:

    RequestMappingHandlerMapping
    RequestMappingHandlerAdapter
    ExceptionHandlerExceptionResolver
    

        还将提供以下支持:

        ① 支持使用 ConversionService 实例对表单参数进行类型转换

        ② 支持使用 @NumberFormat 注解@DateTimeFormat 注解完成数据类型的格式化

        ③ 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证

        ④ 支持使用 @RequestBody@ResponseBody 注解

      2、源码参考:

        BeanDefinitionParse 用于解析 xml 文件中的标签

        继承树结构:

        

         AnnotationDrivenBeanDefinitionParser 用于解析 <mvc: annotation-driven /> 标签

         AnnotationDrivenBeanDefinitionParser 源码参考:

    class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    
        public static final String CONTENT_NEGOTIATION_MANAGER_BEAN_NAME = "mvcContentNegotiationManager";
    
        private static final boolean javaxValidationPresent =
                ClassUtils.isPresent("javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
        private static boolean romePresent =
                ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
        private static final boolean jaxb2Present =
                ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
        private static final boolean jackson2Present =
                ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
                        ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
        private static final boolean jackson2XmlPresent =
                ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
        private static final boolean gsonPresent =
                ClassUtils.isPresent("com.google.gson.Gson", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
    
    
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            Object source = parserContext.extractSource(element);
    
            CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
            parserContext.pushContainingComponent(compDefinition);
    
            RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
    
            RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
            handlerMappingDef.setSource(source);
            handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            handlerMappingDef.getPropertyValues().add("order", 0);
            handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
            String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
    
            if (element.hasAttribute("enable-matrix-variables")) {
                Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
                handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
            }
            else if (element.hasAttribute("enableMatrixVariables")) {
                Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
                handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
            }
    
            configurePathMatchingProperties(handlerMappingDef, element, parserContext);
    
            RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
            RuntimeBeanReference validator = getValidator(element, source, parserContext);
            RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
    
            RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
            bindingDef.setSource(source);
            bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            bindingDef.getPropertyValues().add("conversionService", conversionService);
            bindingDef.getPropertyValues().add("validator", validator);
            bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
    
            ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
            ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
            ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
            String asyncTimeout = getAsyncTimeout(element);
            RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
            ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
            ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
    
            RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
            handlerAdapterDef.setSource(source);
            handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
            handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
            handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
            addResponseBodyAdvice(handlerAdapterDef);
    
            if (element.hasAttribute("ignore-default-model-on-redirect")) {
                Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
                handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
            }
            else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
                // "ignoreDefaultModelOnRedirect" spelling is deprecated
                Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
                handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
            }
    
            if (argumentResolvers != null) {
                handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
            }
            if (returnValueHandlers != null) {
                handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
            }
            if (asyncTimeout != null) {
                handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
            }
            if (asyncExecutor != null) {
                handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
            }
    
            handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
            handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
            String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
    
            String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
            RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
            uriCompContribDef.setSource(source);
            uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
            uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
            parserContext.getReaderContext().getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef);
    
            RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
            csInterceptorDef.setSource(source);
            csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
            RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
            mappedCsInterceptorDef.setSource(source);
            mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
            mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
            String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
    
            RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
            exceptionHandlerExceptionResolver.setSource(source);
            exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
            exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
            exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
            addResponseBodyAdvice(exceptionHandlerExceptionResolver);
    
            String methodExceptionResolverName =
                    parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
    
            RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
            responseStatusExceptionResolver.setSource(source);
            responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            responseStatusExceptionResolver.getPropertyValues().add("order", 1);
            String responseStatusExceptionResolverName =
                    parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
    
            RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
            defaultExceptionResolver.setSource(source);
            defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            defaultExceptionResolver.getPropertyValues().add("order", 2);
            String defaultExceptionResolverName =
                    parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);
    
            parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName));
            parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
            parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
            parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
            parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
            parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
            parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
    
            // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
            MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
    
            parserContext.popAndRegisterContainingComponent();
    
            return null;
        }
    ...
    }

    三、以访问静态和动态资源为例

      只要请求不好使就可以配置 <mvc:annotation-driven /> 标签

      1、既不配置 <mvc:default-servlet-handler>,也不配置 <mvc:annotation-driven />

        效果@RequestMapping映射的资源能访问,静态资源.html/.js/.img 不能访问

        通过 DispatcherServlet 中 dispatch 方法追踪源码:

        handlerMappings:

          

           当发送请求的时候,会按照顺序依次执行 handlerMappings;

           BeanNameUrlHandlerMapping 里面没有保存任何映射信息;

           DefaultAnnotationHandlerMapping 里面保存了映射信息:

           

          动态资源能访问:DefaultAnnotationHandlerMapping 里面的 handlerMap 中保存了每一个资源的映射信息;
          静态资源不能访问:就是 handlerMap 中没有保存静态资源映射的请求;

        handlerAdapters:执行适配器

          

             与此同时 AnnotationMethodHandlerAdapter 帮我们执行目标方法;(过时的)

          另外:conversionService是null(类型转换器是不起作用的)

      2、只配置 <mvc:default-servlet-handler>,不配置 <mvc:annotation-driven />

        效果:静态资源.html/.js/.img 能访问,动态资源不能访问

        handlerMappings

          

          

          动态资源不能访问原因:DefaultAnnotationHandlerMapping  没有了,用 SimpleUrlHandlerMapping 替换了,将所有请求直接交给 Tomcat;
          静态资源能访问: SimpleUrlHandlerMapping 把所有请求都映射给 Tomcat;

        handlerAdapter:

          

           AnnotationMethodHandlerAdapter 没有了,替换成了 SimpleControllerHandlerAdapter。

      3、既配置 <mvc:default-servlet-handler>,也配置 <mvc:annotation-driven />

        效果:动态资源和静态资源都能访问

        handlerMappings

          

        

           

           RequestMappingHandlerMapping:用于处理动态请求;

          SimpleUrlHandlerMapping :将请求直接交给Tomcat,有他,静态资源就没问题;

          先用 RequestMappingHandlerMapping 处理动态请求,如果能找到映射信息,进行处理;如果找不到,使用 SimpleUrlHandlerMapping 交给Tomcat 处理。

        handlerAdapters

          

          原来的 AnnotationMethodHandlerAdapter 被换成 RequestMappingHandlerAdapter 

        AnnotationMethodHandlerAdapter已经过时,Spring3.2推荐RequestMappingHandlerAdapter来替代。所以说,默认情况下,没有配置这两个配置时,HelloWorld 程序可以正常运行,但是,涉及到静态资源查找的时候,就必须配置这个 < mvc:annotation-driven /> 配置了。

  • 相关阅读:
    团队作业第四次—项目系统设计与数据库设计
    团队作业第三次—项目需求分析
    简时——alpha冲刺任务七(5.5)
    简时——alpha冲刺任务六(5.4)
    简时——alpha冲刺任务五(5.3)
    简时——alpha冲刺任务四(5.2)
    简时——alpha冲刺任务三(5.1)
    简时——alpha冲刺日志二(4.30)
    简时——alpha冲刺日志一(4.29)
    TimeMaster—代码规范、冲刺任务与计划
  • 原文地址:https://www.cnblogs.com/niujifei/p/15629637.html
Copyright © 2020-2023  润新知