Add initial support for MVC namespace view resolution config

<mvc:view-resolution /> now allows to configure easily
view resolvers.

Issue: SPR-7093
This commit is contained in:
Siva Prasad Valluru 2013-12-15 18:15:04 +05:30 committed by Rossen Stoyanchev
parent b318880661
commit 92402e7715
6 changed files with 260 additions and 1 deletions

View File

@ -28,13 +28,14 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
*/
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
}
}

View File

@ -0,0 +1,158 @@
package org.springframework.web.servlet.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
import org.springframework.web.servlet.view.tiles2.TilesView;
import org.springframework.web.servlet.view.tiles2.TilesViewResolver;
import org.w3c.dom.Element;
public class ViewResolversBeanDefinitionParser implements BeanDefinitionParser {
private static final String INTERNAL_VIEW_RESOLVER_BEAN_NAME =
"org.springframework.web.servlet.view.InternalResourceViewResolver";
private static final String TILES2_VIEW_RESOLVER_BEAN_NAME =
"org.springframework.web.servlet.view.tiles2.TilesViewResolver";
private static final String TILES2_CONFIGURER_BEAN_NAME =
"org.springframework.web.servlet.view.tiles2.TilesConfigurer";
private static final String BEANNAME_VIEW_RESOLVER_BEAN_NAME =
"org.springframework.web.servlet.view.BeanNameViewResolver";
private static final String FREEMARKER_CONFIGURER_BEAN_NAME =
"org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer";
private static final String FREEMARKER_VIEW_RESOLVER_BEAN_NAME =
"org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver";
private ParserContext parserContext;
private Object source;
public BeanDefinition parse(Element element, ParserContext parserContext) {
this.parserContext=parserContext;
source= parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(),source);
parserContext.pushContainingComponent(compDefinition);
List<Element> viewResolverElements = //DomUtils.getChildElements(element);
DomUtils.getChildElementsByTagName(element, new String[] { "jsp", "tiles","bean-name","freemarker" });
for (Element viewResolverElement : viewResolverElements) {
if ("jsp".equals(viewResolverElement.getLocalName())) {
registerInternalResourceViewResolverBean(parserContext,viewResolverElement);
System.out.println("Registered Internalresource view resolver");
}
if("bean-name".equals(viewResolverElement.getLocalName())){
registerBeanNameViewResolverBean(parserContext,viewResolverElement);
System.out.println("Registered BeanNameViewResolverBean view resolver");
}
if ("tiles".equals(viewResolverElement.getLocalName())) {
registerTilesViewResolverBean(parserContext,viewResolverElement);
registerTilesConfigurerBean(parserContext,viewResolverElement);
}
if("freemarker".equals(viewResolverElement.getLocalName())){
registerFreemarkerViewResolverBean(parserContext,viewResolverElement);
registerFreemarkerConfigurerBean(parserContext,viewResolverElement);
}
}
// MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
parserContext.popAndRegisterContainingComponent();
return null;
}
private void registerBean(String beanName,Map<String,Object> propertyMap,Class beanClass ){
RootBeanDefinition beanDef = new RootBeanDefinition(beanClass);
beanDef.setSource(source);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
for(String propertyName:propertyMap.keySet()){
beanDef.getPropertyValues().add(propertyName, propertyMap.get(propertyName));
}
parserContext.getRegistry().registerBeanDefinition(beanName, beanDef);
parserContext.registerComponent(new BeanComponentDefinition(beanDef, beanName));
}
private void registerFreemarkerConfigurerBean(ParserContext parserContext, Element viewResolverElement) {
String templateLoaderPath=viewResolverElement.getAttribute("templateLoaderPath");
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("templateLoaderPath", templateLoaderPath);
registerBean(FREEMARKER_CONFIGURER_BEAN_NAME, propertyMap, FreeMarkerConfigurer.class);
}
private void registerFreemarkerViewResolverBean(ParserContext parserContext, Element viewResolverElement) {
if (!parserContext.getRegistry().containsBeanDefinition(FREEMARKER_VIEW_RESOLVER_BEAN_NAME)) {
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
propertyMap.put("order", 4);
registerBean(FREEMARKER_VIEW_RESOLVER_BEAN_NAME, propertyMap, FreeMarkerViewResolver.class);
}
}
private void registerBeanNameViewResolverBean(ParserContext parserContext, Element viewResolverElement) {
if (!parserContext.getRegistry().containsBeanDefinition(BEANNAME_VIEW_RESOLVER_BEAN_NAME)) {
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("order", 3);
registerBean(BEANNAME_VIEW_RESOLVER_BEAN_NAME, propertyMap, BeanNameViewResolver.class);
System.out.println("Registered BeanNameViewResolverBean view resolver");
}
}
private void registerTilesConfigurerBean(ParserContext parserContext,Element viewResolverElement) {
if (!parserContext.getRegistry().containsBeanDefinition(TILES2_CONFIGURER_BEAN_NAME)) {
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("definitions", viewResolverElement.getAttribute("definitions"));
registerBean(TILES2_CONFIGURER_BEAN_NAME, propertyMap, TilesConfigurer.class);
}
}
private void registerTilesViewResolverBean(ParserContext parserContext, Element viewResolverElement) {
if (!parserContext.getRegistry().containsBeanDefinition(TILES2_VIEW_RESOLVER_BEAN_NAME)) {
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("viewClass", TilesView.class);
propertyMap.put("order", 1);
registerBean(TILES2_VIEW_RESOLVER_BEAN_NAME, propertyMap, TilesViewResolver.class);
}
}
private void registerInternalResourceViewResolverBean(ParserContext parserContext, Element viewResolverElement) {
if (!parserContext.getRegistry().containsBeanDefinition(INTERNAL_VIEW_RESOLVER_BEAN_NAME)) {
Map<String, Object> propertyMap= new HashMap<String, Object>();
propertyMap.put("prefix", viewResolverElement.getAttribute("prefix"));
propertyMap.put("suffix", viewResolverElement.getAttribute("suffix"));
propertyMap.put("order", 2);
registerBean(INTERNAL_VIEW_RESOLVER_BEAN_NAME, propertyMap, InternalResourceViewResolver.class);
}
}
}

View File

@ -515,5 +515,33 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="view-resolvers" >
<xsd:complexType>
<xsd:all minOccurs="0">
<xsd:element name="jsp" minOccurs="0" >
<xsd:complexType>
<xsd:attribute name="prefix" />
<xsd:attribute name="suffix" />
</xsd:complexType>
</xsd:element>
<xsd:element name="tiles" minOccurs="0" >
<xsd:complexType>
<xsd:attribute name="definitions" />
<xsd:attribute name="viewClass" use="optional" />
</xsd:complexType>
</xsd:element>
<xsd:element name="bean-name" minOccurs="0" />
<xsd:element name="freemarker" minOccurs="0">
<xsd:complexType>
<xsd:attribute name="prefix" />
<xsd:attribute name="suffix" />
<xsd:attribute name="templateLoaderPath" />
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@ -84,6 +84,13 @@ import org.springframework.web.servlet.resource.ResourceResolver;
import org.springframework.web.servlet.resource.ResourceTransformer;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
import org.springframework.web.servlet.view.tiles2.TilesViewResolver;
import static org.junit.Assert.*;
@ -114,6 +121,7 @@ public class MvcNamespaceTests {
handlerMethod = new InvocableHandlerMethod(handler, method);
}
@Test
public void testDefaultConfig() throws Exception {
loadBeanDefinitions("mvc-config.xml", 13);
@ -546,6 +554,33 @@ public class MvcNamespaceTests {
(DeferredResultProcessingInterceptor[]) fieldAccessor.getPropertyValue("deferredResultInterceptors");
assertEquals(1, deferredResultInterceptors.length);
}
@Test
public void testViewResolvers() throws Exception{
loadBeanDefinitions("mvc-config-view-resolvers.xml", 6);
InternalResourceViewResolver internalResourceViewResolver=appContext.getBean(InternalResourceViewResolver.class);
assertNotNull(internalResourceViewResolver);
InternalResourceView jstlView=(InternalResourceView) internalResourceViewResolver.resolveViewName("xyz", Locale.ENGLISH);
assertEquals(jstlView.getUrl(), "/WEB-INF/xyz.jsp");
BeanNameViewResolver beanNameUrlHandlerMapping=appContext.getBean(BeanNameViewResolver.class);
assertNotNull(beanNameUrlHandlerMapping);
TilesConfigurer tilesConfigurer=appContext.getBean(TilesConfigurer.class);
assertNotNull(tilesConfigurer);
TilesViewResolver tilesViewResolver=appContext.getBean(TilesViewResolver.class);
assertNotNull(tilesViewResolver);
FreeMarkerConfigurer freeMarkerConfigurer=appContext.getBean(FreeMarkerConfigurer.class);
assertNotNull(freeMarkerConfigurer);
FreeMarkerViewResolver freeMarkerViewResolver=appContext.getBean(FreeMarkerViewResolver.class);
assertNotNull(freeMarkerViewResolver);
}
@Test
public void testPathMatchingHandlerMappings() throws Exception {

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mvc:view-resolvers>
<mvc:jsp prefix="/WEB-INF/" suffix=".jsp" />
<mvc:bean-name />
<mvc:tiles definitions="/tiles.xml" />
<mvc:freemarker prefix="" suffix=".ftl" templateLoaderPath="/WEB-INF/ftl/" />
</mvc:view-resolvers>
</beans>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="base.definition"
template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="" />
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp" />
<put-attribute name="menu" value="/WEB-INF/jsp/menu.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp" />
</definition>
<definition name="contact" extends="base.definition">
<put-attribute name="title" value="Contact Manager" />
<put-attribute name="body" value="/WEB-INF/jsp/contact.jsp" />
</definition>
</tiles-definitions>