Enhance view controller MVC config
This change adds support for configuring redirect view controllers and also status controllers to the MVC Java config and the MVC namespace. Issue: SPR-11543
This commit is contained in:
@@ -37,6 +37,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
@@ -54,6 +55,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.accept.*;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
@@ -61,6 +63,7 @@ import org.springframework.web.context.request.async.CallableProcessingIntercept
|
||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptorAdapter;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.method.support.CompositeUriComponentsContributor;
|
||||
import org.springframework.web.method.support.InvocableHandlerMethod;
|
||||
@@ -118,10 +121,14 @@ public class MvcNamespaceTests {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
TestMockServletContext servletContext = new TestMockServletContext();
|
||||
appContext = new GenericWebApplicationContext();
|
||||
appContext.setServletContext(new TestMockServletContext());
|
||||
appContext.setServletContext(servletContext);
|
||||
LocaleContextHolder.setLocale(Locale.US);
|
||||
|
||||
String attributeName = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
|
||||
appContext.getServletContext().setAttribute(attributeName, appContext);
|
||||
|
||||
handler = new TestController();
|
||||
Method method = TestController.class.getMethod("testBind", Date.class, TestBean.class, BindingResult.class);
|
||||
handlerMethod = new InvocableHandlerMethod(handler, method);
|
||||
@@ -443,7 +450,7 @@ public class MvcNamespaceTests {
|
||||
SimpleControllerHandlerAdapter adapter = appContext.getBean(SimpleControllerHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
request.setRequestURI("/foo");
|
||||
request = new MockHttpServletRequest("GET", "/foo");
|
||||
chain = mapping2.getHandler(request);
|
||||
assertEquals(4, chain.getInterceptors().length);
|
||||
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor);
|
||||
@@ -452,7 +459,7 @@ public class MvcNamespaceTests {
|
||||
ModelAndView mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertNull(mv.getViewName());
|
||||
|
||||
request.setRequestURI("/myapp/app/bar");
|
||||
request = new MockHttpServletRequest("GET", "/myapp/app/bar");
|
||||
request.setContextPath("/myapp");
|
||||
request.setServletPath("/app");
|
||||
chain = mapping2.getHandler(request);
|
||||
@@ -460,10 +467,10 @@ public class MvcNamespaceTests {
|
||||
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor);
|
||||
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
|
||||
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
|
||||
ModelAndView mv2 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertEquals("baz", mv2.getViewName());
|
||||
mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertEquals("baz", mv.getViewName());
|
||||
|
||||
request.setRequestURI("/myapp/app/");
|
||||
request = new MockHttpServletRequest("GET", "/myapp/app/");
|
||||
request.setContextPath("/myapp");
|
||||
request.setServletPath("/app");
|
||||
chain = mapping2.getHandler(request);
|
||||
@@ -471,8 +478,29 @@ public class MvcNamespaceTests {
|
||||
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor);
|
||||
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
|
||||
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
|
||||
ModelAndView mv3 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertEquals("root", mv3.getViewName());
|
||||
mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertEquals("root", mv.getViewName());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/myapp/app/old");
|
||||
request.setContextPath("/myapp");
|
||||
request.setServletPath("/app");
|
||||
request.setQueryString("a=b");
|
||||
chain = mapping2.getHandler(request);
|
||||
mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
|
||||
assertNotNull(mv.getView());
|
||||
assertEquals(RedirectView.class, mv.getView().getClass());
|
||||
RedirectView redirectView = (RedirectView) mv.getView();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
redirectView.render(Collections.emptyMap(), request, response);
|
||||
assertEquals("/new?a=b", response.getRedirectedUrl());
|
||||
assertEquals(308, response.getStatus());
|
||||
|
||||
request = new MockHttpServletRequest("GET", "/bad");
|
||||
chain = mapping2.getHandler(request);
|
||||
response = new MockHttpServletResponse();
|
||||
mv = adapter.handle(request, response, chain.getHandler());
|
||||
assertNull(mv);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
/** WebSphere gives trailing servlet path slashes by default!! */
|
||||
@@ -524,7 +552,13 @@ public class MvcNamespaceTests {
|
||||
public void testViewControllersDefaultConfig() {
|
||||
loadBeanDefinitions("mvc-config-view-controllers-minimal.xml", 6);
|
||||
|
||||
BeanNameUrlHandlerMapping beanNameMapping = appContext.getBean(BeanNameUrlHandlerMapping.class);
|
||||
SimpleUrlHandlerMapping hm = this.appContext.getBean(SimpleUrlHandlerMapping.class);
|
||||
assertNotNull(hm);
|
||||
assertNotNull(hm.getUrlMap().get("/path"));
|
||||
assertNotNull(hm.getUrlMap().get("/old"));
|
||||
assertNotNull(hm.getUrlMap().get("/bad"));
|
||||
|
||||
BeanNameUrlHandlerMapping beanNameMapping = this.appContext.getBean(BeanNameUrlHandlerMapping.class);
|
||||
assertNotNull(beanNameMapping);
|
||||
assertEquals(2, beanNameMapping.getOrder());
|
||||
}
|
||||
@@ -683,8 +717,8 @@ public class MvcNamespaceTests {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
|
||||
ClassPathResource resource = new ClassPathResource(fileName, AnnotationDrivenBeanDefinitionParserTests.class);
|
||||
reader.loadBeanDefinitions(resource);
|
||||
assertEquals("Bean names: " + Arrays.toString(this.appContext.getBeanDefinitionNames()),
|
||||
expectedBeanCount, appContext.getBeanDefinitionCount());
|
||||
String names = Arrays.toString(this.appContext.getBeanDefinitionNames());
|
||||
assertEquals("Bean names: " + names, expectedBeanCount, appContext.getBeanDefinitionCount());
|
||||
appContext.refresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,22 @@
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.ParameterizableViewController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
/**
|
||||
* Test fixture with a {@link ViewControllerRegistry}.
|
||||
@@ -36,10 +43,16 @@ public class ViewControllerRegistryTests {
|
||||
|
||||
private ViewControllerRegistry registry;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.registry = new ViewControllerRegistry();
|
||||
this.request = new MockHttpServletRequest("GET", "/");
|
||||
this.response = new MockHttpServletResponse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -50,21 +63,59 @@ public class ViewControllerRegistryTests {
|
||||
@Test
|
||||
public void addViewController() {
|
||||
this.registry.addViewController("/path").setViewName("viewName");
|
||||
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
|
||||
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path");
|
||||
assertNotNull(controller);
|
||||
ParameterizableViewController controller = getController("/path");
|
||||
assertEquals("viewName", controller.getViewName());
|
||||
assertNull(controller.getStatusCode());
|
||||
assertFalse(controller.isStatusOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addViewControllerWithDefaultViewName() {
|
||||
this.registry.addViewController("/path");
|
||||
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
|
||||
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path");
|
||||
assertNotNull(controller);
|
||||
ParameterizableViewController controller = getController("/path");
|
||||
assertNull(controller.getViewName());
|
||||
assertNull(controller.getStatusCode());
|
||||
assertFalse(controller.isStatusOnly());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRedirectViewController() throws Exception {
|
||||
this.registry.addRedirectViewController("/path", "/redirectTo");
|
||||
RedirectView redirectView = getRedirectView("/path");
|
||||
this.request.setQueryString("a=b");
|
||||
this.request.setContextPath("/context");
|
||||
redirectView.render(Collections.emptyMap(), this.request, this.response);
|
||||
|
||||
assertEquals(302, this.response.getStatus());
|
||||
assertEquals("/context/redirectTo", this.response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRedirectViewControllerWithCustomSettings() throws Exception {
|
||||
this.registry.addRedirectViewController("/path", "/redirectTo")
|
||||
.setContextRelative(false)
|
||||
.setKeepQueryParams(true)
|
||||
.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
|
||||
|
||||
RedirectView redirectView = getRedirectView("/path");
|
||||
this.request.setQueryString("a=b");
|
||||
this.request.setContextPath("/context");
|
||||
redirectView.render(Collections.emptyMap(), this.request, this.response);
|
||||
|
||||
assertEquals(308, this.response.getStatus());
|
||||
assertEquals("/redirectTo?a=b", response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addStatusController() {
|
||||
this.registry.addStatusController("/path", HttpStatus.NOT_FOUND);
|
||||
ParameterizableViewController controller = getController("/path");
|
||||
assertNull(controller.getViewName());
|
||||
assertEquals(HttpStatus.NOT_FOUND, controller.getStatusCode());
|
||||
assertTrue(controller.isStatusOnly());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void order() {
|
||||
this.registry.addViewController("/path");
|
||||
@@ -76,9 +127,24 @@ public class ViewControllerRegistryTests {
|
||||
assertEquals(2, handlerMapping.getOrder());
|
||||
}
|
||||
|
||||
private ParameterizableViewController getController(String path) {
|
||||
Map<String, ?> urlMap = getHandlerMapping().getUrlMap();
|
||||
ParameterizableViewController controller = (ParameterizableViewController) urlMap.get(path);
|
||||
assertNotNull(controller);
|
||||
return controller;
|
||||
}
|
||||
|
||||
private SimpleUrlHandlerMapping getHandlerMapping() {
|
||||
return (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
|
||||
}
|
||||
|
||||
private RedirectView getRedirectView(String path) {
|
||||
ParameterizableViewController controller = getController("/path");
|
||||
assertNull(controller.getViewName());
|
||||
assertNotNull(controller.getView());
|
||||
assertEquals(RedirectView.class, controller.getView().getClass());
|
||||
return (RedirectView) controller.getView();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.io.FileSystemResourceLoader;
|
||||
@@ -121,8 +122,12 @@ public class WebMvcConfigurationSupportExtensionTests {
|
||||
assertEquals(1, handlerMapping.getOrder());
|
||||
assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass());
|
||||
assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass());
|
||||
HandlerExecutionChain handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
|
||||
assertNotNull(handler.getHandler());
|
||||
chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
|
||||
assertNotNull(chain.getHandler());
|
||||
chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/bad"));
|
||||
assertNotNull(chain.getHandler());
|
||||
chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/old"));
|
||||
assertNotNull(chain.getHandler());
|
||||
|
||||
handlerMapping = (AbstractHandlerMapping) this.config.resourceHandlerMapping();
|
||||
handlerMapping.setApplicationContext(this.context);
|
||||
@@ -130,15 +135,15 @@ public class WebMvcConfigurationSupportExtensionTests {
|
||||
assertEquals(Integer.MAX_VALUE - 1, handlerMapping.getOrder());
|
||||
assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass());
|
||||
assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass());
|
||||
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
|
||||
assertNotNull(handler.getHandler());
|
||||
chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
|
||||
assertNotNull(chain.getHandler());
|
||||
|
||||
handlerMapping = (AbstractHandlerMapping) this.config.defaultServletHandlerMapping();
|
||||
handlerMapping.setApplicationContext(this.context);
|
||||
assertNotNull(handlerMapping);
|
||||
assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
|
||||
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
|
||||
assertNotNull(handler.getHandler());
|
||||
chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
|
||||
assertNotNull(chain.getHandler());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -347,7 +352,9 @@ public class WebMvcConfigurationSupportExtensionTests {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/path");
|
||||
registry.addViewController("/path").setViewName("view");
|
||||
registry.addRedirectViewController("/old", "/new").setStatusCode(HttpStatus.PERMANENT_REDIRECT);
|
||||
registry.addStatusController("/bad", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user