提交 80f4ea13 编写于 作者: S Sebastien Deleuze 提交者: Rossen Stoyanchev

Add Groovy markup templating support to the MVC config

Issue: SPR-11998
上级 b18ed6b7
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
/**
* Parse the <mvc:groovy-markup> MVC namespace element and register a
* GroovyConfigurer bean
*
* @author Sebastien Deleuze
* @since 4.1
*/
public class GroovyMarkupBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
public static final String BEAN_NAME = "mvcGroovyMarkupConfigurer";
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return BEAN_NAME;
}
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer";
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return attributeName.equals("resource-loader-path");
}
}
......@@ -39,6 +39,7 @@ public class MvcNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("tiles", new TilesBeanDefinitionParser());
registerBeanDefinitionParser("freemarker", new FreeMarkerBeanDefinitionParser());
registerBeanDefinitionParser("velocity", new VelocityBeanDefinitionParser());
registerBeanDefinitionParser("groovy-markup", new GroovyMarkupBeanDefinitionParser());
}
}
......@@ -16,9 +16,7 @@
package org.springframework.web.servlet.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
......@@ -37,6 +35,7 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.ViewResolverComposite;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
import org.w3c.dom.Element;
......@@ -77,7 +76,7 @@ public class ViewResolversBeanDefinitionParser implements BeanDefinitionParser {
ManagedList<Object> resolvers = new ManagedList<Object>(4);
resolvers.setSource(context.extractSource(element));
String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "bean", "ref"};
String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy-markup", "bean", "ref"};
for (Element resolverElement : DomUtils.getChildElementsByTagName(element, names)) {
String name = resolverElement.getLocalName();
......@@ -109,6 +108,11 @@ public class ViewResolversBeanDefinitionParser implements BeanDefinitionParser {
else if ("bean-name".equals(name)) {
resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
}
else if ("groovy-markup".equals(name)) {
resolverBeanDef = new RootBeanDefinition(GroovyMarkupViewResolver.class);
resolverBeanDef.getPropertyValues().add("suffix", ".tpl");
addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
}
else {
// Should never happen
throw new IllegalStateException("Unexpected element name: " + name);
......
......@@ -30,6 +30,8 @@ import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
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.groovy.GroovyMarkupConfigurer;
import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
......@@ -198,7 +200,7 @@ public class ViewResolverRegistry {
/**
* Register Velocity view resolver with an empty default view name
* prefix, a default suffix of ".vm".
* prefix and a default suffix of ".vm".
*
* <p><strong>Note</strong> that you must also configure Velocity by adding a
* {@link org.springframework.web.servlet.view.velocity.VelocityConfigurer} bean.
......@@ -224,6 +226,22 @@ public class ViewResolverRegistry {
this.viewResolvers.add(resolver);
}
/**
* Register a Groovy Markup Template view resolver with an empty default view name
* prefix and a default suffix of ".tpl".
*/
public UrlBasedViewResolverRegistration groovyMarkup() {
if (this.applicationContext != null && !hasBeanOfType(GroovyMarkupConfigurer.class)) {
throw new BeanInitializationException("In addition to a Groovy Markup Template view resolver " +
"there must also be a single GroovyMarkupConfig bean in this web application context " +
"(or its parent): GroovyMarkupConfigurer is the usual implementation. " +
"This bean may be given any name.");
}
GroovyMarkupRegistration registration = new GroovyMarkupRegistration();
this.viewResolvers.add(registration.getViewResolver());
return registration;
}
/**
* Register a {@link ViewResolver} bean instance. This may be useful to
* configure a custom (or 3rd party) resolver implementation. It may also be
......@@ -282,4 +300,12 @@ public class ViewResolverRegistry {
}
}
private static class GroovyMarkupRegistration extends UrlBasedViewResolverRegistration {
private GroovyMarkupRegistration() {
super(new GroovyMarkupViewResolver());
getViewResolver().setSuffix(".tpl");
}
}
}
......@@ -753,6 +753,16 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="groovy-markup" type="urlViewResolverType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Register a GroovyMarkupViewResolver.
By default ".tpl" is configured as a view name suffix.
To configure Groovy Markup Template you must also add a top-level <mvc:groovy-markup> element.
or declare a GroovyMarkupConfigurer bean.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="beans:bean">
<xsd:annotation>
<xsd:documentation><![CDATA[
......@@ -853,4 +863,22 @@
</xsd:complexType>
</xsd:element>
<xsd:element name="groovy-markup">
<xsd:annotation>
<xsd:documentation><![CDATA[
Configure Groovy Markup Template for view resolution by registering a GroovyMarkupConfigurer bean.
This is a shortcut alternative to declaring a GroovyMarkupConfigurer bean directly.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="resource-loader-path" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The Groovy Markup Template resource loader path via a Spring resource location.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
......@@ -84,6 +84,8 @@ import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
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.servlet.view.groovy.GroovyMarkupConfigurer;
import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.servlet.view.*;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
......@@ -561,11 +563,11 @@ public class MvcNamespaceTests {
@Test
public void testViewResolution() throws Exception {
loadBeanDefinitions("mvc-config-view-resolution.xml", 5);
loadBeanDefinitions("mvc-config-view-resolution.xml", 6);
ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class);
assertNotNull(compositeResolver);
assertEquals(7, compositeResolver.getViewResolvers().size());
assertEquals(8, compositeResolver.getViewResolvers().size());
assertEquals(0, compositeResolver.getOrder());
List<ViewResolver> resolvers = compositeResolver.getViewResolvers();
......@@ -593,8 +595,15 @@ public class MvcNamespaceTests {
assertEquals(".vm", accessor.getPropertyValue("suffix"));
assertEquals(0, accessor.getPropertyValue("cacheLimit"));
assertEquals(InternalResourceViewResolver.class, resolvers.get(5).getClass());
resolver = resolvers.get(5);
GroovyMarkupViewResolver groovyMarkupViewResolver = (GroovyMarkupViewResolver) resolver;
accessor = new DirectFieldAccessor(resolver);
assertEquals("", accessor.getPropertyValue("prefix"));
assertEquals(".tpl", accessor.getPropertyValue("suffix"));
assertEquals(1024, accessor.getPropertyValue("cacheLimit"));
assertEquals(InternalResourceViewResolver.class, resolvers.get(6).getClass());
assertEquals(InternalResourceViewResolver.class, resolvers.get(7).getClass());
TilesConfigurer tilesConfigurer = appContext.getBean(TilesConfigurer.class);
......@@ -616,11 +625,16 @@ public class MvcNamespaceTests {
assertNotNull(velocityConfigurer);
accessor = new DirectFieldAccessor(velocityConfigurer);
assertEquals("/test", accessor.getPropertyValue("resourceLoaderPath"));
GroovyMarkupConfigurer groovyMarkupConfigurer = appContext.getBean(GroovyMarkupConfigurer.class);
assertNotNull(groovyMarkupConfigurer);
accessor = new DirectFieldAccessor(groovyMarkupConfigurer);
assertEquals("/test", accessor.getPropertyValue("resourceLoaderPath"));
}
@Test
public void testViewResolutionWithContentNegotiation() throws Exception {
loadBeanDefinitions("mvc-config-view-resolution-content-negotiation.xml", 5);
loadBeanDefinitions("mvc-config-view-resolution-content-negotiation.xml", 6);
ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class);
assertNotNull(compositeResolver);
......@@ -630,7 +644,7 @@ public class MvcNamespaceTests {
List<ViewResolver> resolvers = compositeResolver.getViewResolvers();
assertEquals(ContentNegotiatingViewResolver.class, resolvers.get(0).getClass());
ContentNegotiatingViewResolver cnvr = (ContentNegotiatingViewResolver) resolvers.get(0);
assertEquals(5, cnvr.getViewResolvers().size());
assertEquals(6, cnvr.getViewResolvers().size());
assertEquals(1, cnvr.getDefaultViews().size());
assertTrue(cnvr.isUseNotAcceptableStatusCode());
......
......@@ -27,12 +27,12 @@ import org.springframework.mock.web.test.MockServletConfig;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
......@@ -71,6 +71,12 @@ public class ViewResolutionIntegrationTests {
assertEquals("/WEB-INF/index.jsp", response.getForwardedUrl());
}
@Test
public void groovyMarkup() throws Exception {
MockHttpServletResponse response = runTest(GroovyMarkupWebConfig.class);
assertEquals("<html><body>Hello World!</body></html>", response.getContentAsString());
}
@Test
public void freemarkerInvalidConfig() throws Exception {
this.thrown.expectMessage("In addition to a FreeMarker view resolver ");
......@@ -89,6 +95,12 @@ public class ViewResolutionIntegrationTests {
runTest(InvalidTilesWebConfig.class);
}
@Test
public void groovyMarkupInvalidConfig() throws Exception {
this.thrown.expectMessage("In addition to a Groovy Markup Template view resolver ");
runTest(InvalidGroovyMarkupWebConfig.class);
}
private MockHttpServletResponse runTest(Class<?> configClass) throws ServletException, IOException {
String basePath = "org/springframework/web/servlet/config/annotation";
......@@ -112,7 +124,7 @@ public class ViewResolutionIntegrationTests {
static class SampleController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String tiles(@ModelAttribute("model") ModelMap model) {
public String sample(ModelMap model) {
model.addAttribute("hello", "Hello World!");
return "index";
}
......@@ -175,6 +187,22 @@ public class ViewResolutionIntegrationTests {
}
}
@Configuration
static class GroovyMarkupWebConfig extends AbstractWebConfig {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.groovyMarkup();
}
@Bean
public GroovyMarkupConfigurer groovyMarkupConfigurer() {
GroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();
configurer.setResourceLoaderPath("/WEB-INF/");
return configurer;
}
}
@Configuration
static class InvalidFreeMarkerWebConfig extends WebMvcConfigurationSupport {
......@@ -202,4 +230,13 @@ public class ViewResolutionIntegrationTests {
}
}
@Configuration
static class InvalidGroovyMarkupWebConfig extends WebMvcConfigurationSupport {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.groovyMarkup();
}
}
}
......@@ -28,6 +28,8 @@ import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
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.groovy.GroovyMarkupConfigurer;
import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
......@@ -57,6 +59,7 @@ public class ViewResolverRegistryTests {
context.registerSingleton("freeMarkerConfigurer", FreeMarkerConfigurer.class);
context.registerSingleton("velocityConfigurer", VelocityConfigurer.class);
context.registerSingleton("tilesConfigurer", TilesConfigurer.class);
context.registerSingleton("groovyMarkupConfigurer", GroovyMarkupConfigurer.class);
this.registry = new ViewResolverRegistry();
this.registry.setApplicationContext(context);
this.registry.setContentNegotiationManager(new ContentNegotiationManager());
......@@ -165,6 +168,20 @@ public class ViewResolverRegistryTests {
checkPropertyValues(resolver, "prefix", "", "suffix", ".ftl");
}
@Test
public void groovyMarkup() {
this.registry.groovyMarkup().prefix("/").suffix(".groovy").cache(true);
GroovyMarkupViewResolver resolver = checkAndGetResolver(GroovyMarkupViewResolver.class);
checkPropertyValues(resolver, "prefix", "/", "suffix", ".groovy", "cacheLimit", 1024);
}
@Test
public void groovyMarkupDefaultValues() {
this.registry.groovyMarkup();
GroovyMarkupViewResolver resolver = checkAndGetResolver(GroovyMarkupViewResolver.class);
checkPropertyValues(resolver, "prefix", "", "suffix", ".tpl");
}
@Test
public void contentNegotiation() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
......
<html><body>${model.hello}</body></html>
\ No newline at end of file
<html><body>${hello}</body></html>
\ No newline at end of file
......@@ -6,7 +6,7 @@
<title>My First Web Application Using Spring MVC</title>
</head>
<body>
${model.hello}
${hello}
</body>
</html>
<html><body>${model.hello}</body></html>
\ No newline at end of file
<html><body>${hello}</body></html>
\ No newline at end of file
......@@ -25,6 +25,7 @@
<mvc:tiles />
<mvc:freemarker />
<mvc:velocity />
<mvc:groovy-markup />
</mvc:view-resolvers>
<mvc:tiles check-refresh="true">
......@@ -37,5 +38,7 @@
<mvc:velocity resource-loader-path="/org/springframework/web/servlet/view" />
<mvc:groovy-markup />
</beans>
\ No newline at end of file
......@@ -12,6 +12,7 @@
<mvc:tiles />
<mvc:freemarker prefix="freemarker-" suffix=".freemarker" view-names="my*,*Report" />
<mvc:velocity cache-views="false" />
<mvc:groovy-markup />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
<ref bean="customResolver" />
</mvc:view-resolvers>
......@@ -30,5 +31,7 @@
<mvc:velocity resource-loader-path="/test" />
<mvc:groovy-markup resource-loader-path="/test" />
</beans>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册