文档章节

Spring MVC <mvc:view-resolvers> 标签解析

秋风醉了
 秋风醉了
发布于 2015/07/19 16:59
字数 968
阅读 155
收藏 0

Spring MVC <mvc:view-resolvers> 标签解析

<mvc:view-resolvers>的解析类是 ViewResolversBeanDefinitionParser。关键部分的代码:

public BeanDefinition parse(Element element, ParserContext context) {
    Object source = context.extractSource(element);
    context.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), source));

    ManagedList<Object> resolvers = new ManagedList<Object>(4);
    resolvers.setSource(context.extractSource(element));
    String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy", "bean", "ref"};

    for (Element resolverElement : DomUtils.getChildElementsByTagName(element, names)) {
        String name = resolverElement.getLocalName();
        if ("bean".equals(name) || "ref".equals(name)) {
            resolvers.add(context.getDelegate().parsePropertySubElement(resolverElement, null));
            continue;
        }
        RootBeanDefinition resolverBeanDef = null;
        if ("jsp".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(InternalResourceViewResolver.class);
            resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
            resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("tiles".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("freemarker".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(FreeMarkerViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("velocity".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(VelocityViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".vm");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("groovy".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(GroovyMarkupViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".tpl");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("bean-name".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
        }
        else {
            // Should never happen
            throw new IllegalStateException("Unexpected element name: " + name);
        }
        resolverBeanDef.setSource(source);
        resolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        resolvers.add(resolverBeanDef);
    }

    String beanName = VIEW_RESOLVER_BEAN_NAME;
    RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(ViewResolverComposite.class);
    compositeResolverBeanDef.setSource(source);
    compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    names = new String[] {"content-negotiation"};
    List<Element> contentnNegotiationElements = DomUtils.getChildElementsByTagName(element, names);
    if (contentnNegotiationElements.isEmpty()) {
        compositeResolverBeanDef.getPropertyValues().add("viewResolvers", resolvers);
    }
    else if (contentnNegotiationElements.size() == 1) {
        BeanDefinition beanDef = createContentNegotiatingViewResolver(contentnNegotiationElements.get(0), context);
        beanDef.getPropertyValues().add("viewResolvers", resolvers);
        ManagedList<Object> list = new ManagedList<Object>(1);
        list.add(beanDef);
        compositeResolverBeanDef.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        compositeResolverBeanDef.getPropertyValues().add("viewResolvers", list);
    }
    else if (contentnNegotiationElements.size() > 1) {
        throw new IllegalArgumentException("Only one <content-negotiation> element is allowed.");
    }

    if (element.hasAttribute("order")) {
        compositeResolverBeanDef.getPropertyValues().add("order", element.getAttribute("order"));
    }

    context.getReaderContext().getRegistry().registerBeanDefinition(beanName, compositeResolverBeanDef);
    context.registerComponent(new BeanComponentDefinition(compositeResolverBeanDef, beanName));
    context.popAndRegisterContainingComponent();
    return null;
}

如下的<mvc:view-resolvers>标签的配置:

<!-- 配置视图解析器-->
<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                <property name="jsonpParameterNames">
                    <set>
                        <value>jsonp</value>
                        <value>callback</value>
                    </set>
                </property>
            </bean>
        </mvc:default-views>
    </mvc:content-negotiation>
    <!-- JSP的视图解析器-->
    <mvc:jsp prefix="/WEB-INF/views/"/>
</mvc:view-resolvers>

那么他是如何解析的呢?通过debug代码可以很清晰的了解到。

关键的流程如下,首先解析<mvc:view-resolvers>标签下的子标签,包括以下子标签:

 String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy", "bean", "ref"};

对于这些子标签的处理,如下

if ("jsp".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        InternalResourceViewResolver.class);
    resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
    resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("tiles".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("freemarker".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        FreeMarkerViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("velocity".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(VelocityViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".vm");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("groovy".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        GroovyMarkupViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".tpl");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("bean-name".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
} else {
    // Should never happen
    throw new IllegalStateException("Unexpected element name: " + name);
}

如何配置了这几种常见的视图解析器, 那么在这里就会实例化(注入)相应的视图解析器。

比较常见的视图解析器有:

  1. InternalResourceViewResolver:UrlBasedViewResolver 的子类,通常用于查找 JSP(类 InternalResourceView)和 JSTL(类 JstlView,InternalResourceView 的子类)等视图。

  2. TilesViewResolver:(一种动态模板视图解析器)

  3. FreeMarkerViewResolver:(FreeMarker的视图解析器)

  4. VelocityViewResolver:(Velocity的视图解析器)

  5. GroovyMarkupViewResolver:(基于Groovy 的一种DSL风格的模板视图解析器)

  6. BeanNameViewResolver:

 

然后是处理其他的子标签,只有content-negotiation子标签:

names = new String[] {"content-negotiation"};

处理content-negotiation子标签的代码如下,

String beanName = VIEW_RESOLVER_BEAN_NAME;
RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(
    ViewResolverComposite.class);
compositeResolverBeanDef.setSource(source);
compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

names = new String[] { "content-negotiation" };
List<Element> contentnNegotiationElements = DomUtils
    .getChildElementsByTagName(element, names);
if (contentnNegotiationElements.isEmpty()) {
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        resolvers);
} else if (contentnNegotiationElements.size() == 1) {
    BeanDefinition beanDef = createContentNegotiatingViewResolver(
        contentnNegotiationElements.get(0), context);
    beanDef.getPropertyValues().add("viewResolvers", resolvers);
    ManagedList<Object> list = new ManagedList<Object>(1);
    list.add(beanDef);
    compositeResolverBeanDef.getPropertyValues().add("order",
        Ordered.HIGHEST_PRECEDENCE);
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        list);
} else if (contentnNegotiationElements.size() > 1) {
    throw new IllegalArgumentException(
        "Only one <content-negotiation> element is allowed.");
}

再来看他是怎么创建 ContentNegotiatingViewResolver 的 。

BeanDefinition beanDef = createContentNegotiatingViewResolver(contentnNegotiationElements.get(0), context);

方法createContentNegotiatingViewResolver

private BeanDefinition createContentNegotiatingViewResolver(Element resolverElement, ParserContext context) {
    RootBeanDefinition beanDef = new RootBeanDefinition(ContentNegotiatingViewResolver.class);
    beanDef.setSource(context.extractSource(resolverElement));
    beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    MutablePropertyValues values = beanDef.getPropertyValues();
    //<content-negotiation>标签下的子标签 default-views
    List<Element> elements = DomUtils.getChildElementsByTagName(resolverElement, new String[] {"default-views"});
    if (!elements.isEmpty()) {
        ManagedList<Object> list = new ManagedList<Object>();
        for (Element element : DomUtils.getChildElementsByTagName(elements.get(0), "bean", "ref")) {
            list.add(context.getDelegate().parsePropertySubElement(element, null));
        }
        values.add("defaultViews", list);
    }
    if (resolverElement.hasAttribute("use-not-acceptable")) {
        values.add("useNotAcceptableStatusCode", resolverElement.getAttribute("use-not-acceptable"));
    }
    String beanName = AnnotationDrivenBeanDefinitionParser.CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
    if (context.getRegistry().containsBeanDefinition(beanName)) {
        values.add("contentNegotiationManager", new RuntimeBeanReference(beanName));
    }
    return beanDef;
}

至此 ,<mvc:view-resolvers>标签就处理完了。

要注意到,如果没有配置content-negotiation子标签,那么只有ViewResolverComposite的实例对象包含了所有配置的视图解析器。

compositeResolverBeanDef.getPropertyValues().add("viewResolvers",resolvers);

否则,那么创建ContentNegotiatingViewResolver,并设置ContentNegotiatingViewResolver的viewResolvers的集合,同时设置 ViewResolverComposite 的viewResolvers集合,

但只包含一个ContentNegotiatingViewResolver的实例。

 BeanDefinition beanDef = createContentNegotiatingViewResolver(
        contentnNegotiationElements.get(0), context);
    beanDef.getPropertyValues().add("viewResolvers", resolvers);
    ManagedList<Object> list = new ManagedList<Object>(1);
    list.add(beanDef);
    compositeResolverBeanDef.getPropertyValues().add("order",
        Ordered.HIGHEST_PRECEDENCE);
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        list);

=================END=================

© 著作权归作者所有

秋风醉了
粉丝 247
博文 542
码字总数 412294
作品 0
朝阳
程序员
私信 提问
Spring4.1新特性——Spring MVC增强

1、GroovyWebApplicationContext 在Spring 4.1之前没有提供Web集成的ApplicationContext,在《Spring4新特性——Groovy Bean定义DSL》中我们自己去实现的com.sishuok.spring4.context.suppo...

莱茵河水怪v241Beta
2015/07/23
0
0
springmvc源码解析合集

更多精彩源码解析文章请关注”天河聊架构“微信公众号。 springmvc源码解析之组件介绍 springmvc源码解析之配置加载SpringServletContainerInitializer springmvc源码解析之配置加载Context...

天河2018
03/27
0
0
spring web 4.1处理json

Spring mvc处理json,我们都知道使用@ResponseBody,处理xml也是用此注解。如果想spring mvc的使用@ResponseBody注解处理json,我们需要加入一些处理bean,也可以使用默认spring提供的。 通过...

引鸩怼孑
2015/07/09
0
0
Spring MVC温故而知新 – 从零开始

Spring MVC简介 Spring MVC是一款基于MVC架构模式的轻量级Web框架,目的是将Web开发模块化,对整体架构进行解耦。 Spring MVC有一下优点: 作为Spring框架的一部分,拥有Spring的优点(IOC,A...

Java工程师-Distance
2018/05/18
0
0
SpringMVC基础知识 (1)

1. Spring体系结构  如图所示,MyBatis属于其管理下的ORM(持久层映射)层,而SpringMVC则属于Web-MVC处理层的框架。 Spring MVC有以下优点: Spring MVC技术是与Spring框架结合而成的,它同...

LeaveStyle
2018/08/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【阴阳师】真蛇10层记录

蛇切黑体系 追月神 散件一速,速度越高越好(220+) 镰鼬 招财二速,速度211以上; 山兔 火灵三速,速度180-200均可; 丑女 心眼四速,速度170左右即可; 大蛇 蚌精暴击套。速度高于阴阳师即...

Areya
16分钟前
3
0
js动态设置元素高度

this.$refs.xxx.style.height= this.contentHeight; 元素需要绑定

Carbenson
53分钟前
2
0
今天的学习

今天学到了ci框架中的查询语句的where条件语句: 1、$this->db->select('')->from('')->where('id = ??')->get()->result_array();2、$this->db->select('')->from('')->where('id', '??'......

墨冥
今天
2
0
MySQL在高并发下的订单撮合、系统使用、共享锁与排他锁保证数据一致性

前序 距离上次择文发表,两月余久。2018年也即将要结束了,目前的工作依然是与区块链应用相关的,也很荣幸在9月初受邀签约出版暂名为《区块链以太坊DApp实战开发》一书,预计在明年年初出版。...

我最喜欢三大框架
今天
2
0
深入理解Flutter多线程

该文章属于<简书 — 刘小壮>原创,转载请注明: <简书 — 刘小壮> https://www.jianshu.com/p/54da18ed1a9e Flutter默认是单线程任务处理的,如果不开启新的线程,任务默认在主线程中处理。 ...

刘小壮
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部