Spring MVC 標籤解析

Spring MVC <mvc:view-resolvers> 標籤解析web

<mvc:view-resolvers>的解析類是 ViewResolversBeanDefinitionParser。關鍵部分的代碼:spring

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>標籤的配置:json

<!-- 配置視圖解析器-->
<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

關鍵的流程以下,首先解析<mvc:view-resolvers>標籤下的子標籤,包括如下子標籤:app

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

對於這些子標籤的處理,以下jsp

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

如何配置了這幾種常見的視圖解析器, 那麼在這裏就會實例化(注入)相應的視圖解析器。jsonp

比較常見的視圖解析器有:spa

  1. InternalResourceViewResolver:UrlBasedViewResolver 的子類,一般用於查找 JSP(類 InternalResourceView)和 JSTL(類 JstlView,InternalResourceView 的子類)等視圖。debug

  2. TilesViewResolver:(一種動態模板視圖解析器)code

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

相關文章
相關標籤/搜索