Polish view controller MVC config

This commit is contained in:
Rossen Stoyanchev 2014-07-17 11:23:45 -04:00
parent 61ec8fd236
commit 7f7fd7d311
5 changed files with 81 additions and 74 deletions

View File

@ -19,7 +19,6 @@ package org.springframework.web.servlet.config;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
@ -36,6 +35,7 @@ import org.w3c.dom.Element;
*
* @author Keith Donald
* @author Christian Dupuis
* @author Rossen Stoyanchev
* @since 3.0
*/
class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
@ -50,48 +50,45 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
Object source = parserContext.extractSource(element);
// Register SimpleUrlHandlerMapping for view controllers
BeanDefinition handlerMappingDef = registerHandlerMapping(parserContext, source);
BeanDefinition handlerMapping = registerHandlerMapping(parserContext, source);
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
// Create view controller bean definition
RootBeanDefinition viewControllerDef = new RootBeanDefinition(ParameterizableViewController.class);
viewControllerDef.setSource(source);
RootBeanDefinition controller = new RootBeanDefinition(ParameterizableViewController.class);
controller.setSource(source);
if (element.hasAttribute("view-name")) {
viewControllerDef.getPropertyValues().add("viewName", element.getAttribute("view-name"));
controller.getPropertyValues().add("viewName", element.getAttribute("view-name"));
}
Map<String, BeanDefinition> urlMap;
if (handlerMappingDef.getPropertyValues().contains("urlMap")) {
urlMap = (Map<String, BeanDefinition>) handlerMappingDef.getPropertyValues().getPropertyValue("urlMap").getValue();
if (handlerMapping.getPropertyValues().contains("urlMap")) {
urlMap = (Map<String, BeanDefinition>) handlerMapping.getPropertyValues().getPropertyValue("urlMap").getValue();
}
else {
urlMap = new ManagedMap<String, BeanDefinition>();
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
handlerMapping.getPropertyValues().add("urlMap", urlMap);
}
urlMap.put(element.getAttribute("path"), viewControllerDef);
urlMap.put(element.getAttribute("path"), controller);
return null;
}
private BeanDefinition registerHandlerMapping(ParserContext parserContext, Object source) {
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
RuntimeBeanReference pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(null, parserContext, source);
RuntimeBeanReference pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(null, parserContext, source);
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.getPropertyValues().add("order", "1");
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef).add("urlPathHelper", pathHelperRef);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
return handlerMappingDef;
private BeanDefinition registerHandlerMapping(ParserContext context, Object source) {
if (context.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
return context.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
}
else {
return parserContext.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
}
RootBeanDefinition beanDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
context.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, beanDef);
context.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_BEAN_NAME));
beanDef.setSource(source);
beanDef.getPropertyValues().add("order", "1");
beanDef.getPropertyValues().add("pathMatcher", MvcNamespaceUtils.registerPathMatcher(null, context, source));
beanDef.getPropertyValues().add("urlPathHelper", MvcNamespaceUtils.registerUrlPathHelper(null, context, source));
return beanDef;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
@ -21,7 +21,7 @@ import org.springframework.web.servlet.RequestToViewNameTranslator;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
/**
* Encapsulates information required to create a view controller.
* Assist with the registration of a single view controller.
*
* @author Rossen Stoyanchev
* @author Keith Donald
@ -33,37 +33,38 @@ public class ViewControllerRegistration {
private String viewName;
/**
* Creates a {@link ViewControllerRegistration} with the given URL path. When a request matches
* to the given URL path this view controller will process it.
* Creates a registration for the given URL path (or path pattern).
*/
public ViewControllerRegistration(String urlPath) {
Assert.notNull(urlPath, "A URL path is required to create a view controller.");
Assert.notNull(urlPath, "'urlPath' is required.");
this.urlPath = urlPath;
}
/**
* Sets the view name to use for this view controller. This field is optional. If not specified the
* view controller will return a {@code null} view name, which will be resolved through the configured
* {@link RequestToViewNameTranslator}. By default that means "/foo/bar" would resolve to "foo/bar".
* Set the view name to return.
*
* <p>If not specified, the view controller returns {@code null} as the view
* name in which case the configured {@link RequestToViewNameTranslator}
* selects the view. In effect {@code DefaultRequestToViewNameTranslator}
* translates "/foo/bar" to "foo/bar".
*
* @see org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
*/
public void setViewName(String viewName) {
this.viewName = viewName;
}
/**
* Returns the URL path for the view controller.
*/
protected String getUrlPath() {
return urlPath;
return this.urlPath;
}
/**
* Returns the view controllers.
*/
protected Object getViewController() {
ParameterizableViewController controller = new ParameterizableViewController();
controller.setViewName(viewName);
controller.setViewName(this.viewName);
return controller;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
@ -26,9 +26,9 @@ import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
/**
* Stores registrations of view controllers. A view controller does nothing more than return a specified
* view name. It saves you from having to write a controller when you want to forward the request straight
* through to a view such as a JSP.
* Enables the registration of view controllers that have no logic other than to
* return the view name they're configured with. This is an alternative to
* writing a controller manually to do the same.
*
* @author Rossen Stoyanchev
* @author Keith Donald
@ -40,36 +40,41 @@ public class ViewControllerRegistry {
private int order = 1;
/**
* Register a view controller mapped to the given URL path or URL path pattern.
*/
public ViewControllerRegistration addViewController(String urlPath) {
ViewControllerRegistration registration = new ViewControllerRegistration(urlPath);
registrations.add(registration);
this.registrations.add(registration);
return registration;
}
/**
* Specify the order to use for ViewControllers mappings relative to other {@link HandlerMapping}s
* configured in the Spring MVC application context. The default value for view controllers is 1,
* which is 1 higher than the value used for annotated controllers.
* Specify the order to use for the {@code HandlerMapping} used to map view
* controllers relative to other handler mappings configured in Spring MVC.
* <p>By default this is set to 1, i.e. right after annotated controllers,
* which are ordered at 0.
*/
public void setOrder(int order) {
this.order = order;
}
/**
* Returns a handler mapping with the mapped ViewControllers; or {@code null} in case of no registrations.
* Return the {@code HandlerMapping} that contains the registered view
* controller mappings, or {@code null} for no registrations.
*/
protected AbstractHandlerMapping getHandlerMapping() {
if (registrations.isEmpty()) {
if (this.registrations.isEmpty()) {
return null;
}
Map<String, Object> urlMap = new LinkedHashMap<String, Object>();
for (ViewControllerRegistration registration : registrations) {
for (ViewControllerRegistration registration : this.registrations) {
urlMap.put(registration.getUrlPath(), registration.getViewController());
}
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(order);
handlerMapping.setOrder(this.order);
handlerMapping.setUrlMap(urlMap);
return handlerMapping;
}

View File

@ -583,7 +583,7 @@
<xsd:attribute name="path" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The URL path the view is mapped to.
The URL path or (path pattern) the controller is mapped to.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@ -591,8 +591,10 @@
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the view to render. Optional.
If not specified, the view name will be determined from the current HttpServletRequest
by the DispatcherServlet's RequestToViewNameTranslator.
If not specified, the view controller will return null as the view name in which case
the configured RequestToViewNameTranslator selects the view.
In effect the DefaultRequestToViewNameTranslator translates "/foo/bar" to "foo/bar".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* 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.
@ -36,47 +36,49 @@ public class ViewControllerRegistryTests {
private ViewControllerRegistry registry;
@Before
public void setUp() {
registry = new ViewControllerRegistry();
this.registry = new ViewControllerRegistry();
}
@Test
public void noViewControllers() throws Exception {
assertNull(registry.getHandlerMapping());
assertNull(this.registry.getHandlerMapping());
}
@Test
public void addViewController() {
registry.addViewController("/path");
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path");
assertNotNull(controller);
assertNull(controller.getViewName());
}
@Test
public void addViewControllerWithViewName() {
registry.addViewController("/path").setViewName("viewName");
this.registry.addViewController("/path").setViewName("viewName");
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path");
assertNotNull(controller);
assertEquals("viewName", controller.getViewName());
}
@Test
public void addViewControllerWithDefaultViewName() {
this.registry.addViewController("/path");
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path");
assertNotNull(controller);
assertNull(controller.getViewName());
}
@Test
public void order() {
registry.addViewController("/path");
this.registry.addViewController("/path");
SimpleUrlHandlerMapping handlerMapping = getHandlerMapping();
assertEquals(1, handlerMapping.getOrder());
registry.setOrder(2);
this.registry.setOrder(2);
handlerMapping = getHandlerMapping();
assertEquals(2, handlerMapping.getOrder());
}
private SimpleUrlHandlerMapping getHandlerMapping() {
return (SimpleUrlHandlerMapping) registry.getHandlerMapping();
return (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
}
}