Only enable full path optimization when there's one DispatcherServlet
Previously, UrlPathHelper's full path optimization was enabled when there was a dispatcher servlet mapped to /. The UrlPathHelper is used across Spring MVC and if there are multiple dispatcher servlets they all share the sample UrlPathHelper. This meant that any additional dispatcher servlets mapping to locations other than / would not be able to map requests correctly as the UrlPathHelper would use the full path, ignoring the url mapping of the dispatcher servlet. This commit updates the MVC auto-configuration so that use of the full path is only enabled if there's a single dispatcher servlet registration. Fixes gh-22682
This commit is contained in:
parent
980ddcffd0
commit
1270af90c2
|
|
@ -56,6 +56,7 @@ import org.springframework.boot.autoconfigure.web.format.WebConversionService;
|
|||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.Format;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
||||
|
|
@ -191,18 +192,22 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
|
||||
|
||||
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
|
||||
|
||||
final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
|
||||
|
||||
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
|
||||
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
|
||||
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
|
||||
ObjectProvider<DispatcherServletPath> dispatcherServletPath) {
|
||||
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
|
||||
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
|
||||
this.resourceProperties = resourceProperties;
|
||||
this.mvcProperties = mvcProperties;
|
||||
this.beanFactory = beanFactory;
|
||||
this.messageConvertersProvider = messageConvertersProvider;
|
||||
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
|
||||
this.dispatcherServletPath = dispatcherServletPath;
|
||||
this.servletRegistrations = servletRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -234,7 +239,7 @@ public class WebMvcAutoConfiguration {
|
|||
this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
|
||||
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
|
||||
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
|
||||
if (servletUrlMapping.equals("/")) {
|
||||
if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
|
||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
urlPathHelper.setAlwaysUseFullPath(true);
|
||||
configurer.setUrlPathHelper(urlPathHelper);
|
||||
|
|
@ -242,6 +247,11 @@ public class WebMvcAutoConfiguration {
|
|||
});
|
||||
}
|
||||
|
||||
private boolean singleDispatcherServlet() {
|
||||
return this.servletRegistrations.stream().map(ServletRegistrationBean::getServlet)
|
||||
.filter(DispatcherServlet.class::isInstance).count() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import org.springframework.boot.test.context.runner.ContextConsumer;
|
|||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter;
|
||||
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
|
@ -84,6 +85,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|||
import org.springframework.web.filter.FormContentFilter;
|
||||
import org.springframework.web.filter.HiddenHttpMethodFilter;
|
||||
import org.springframework.web.filter.RequestContextFilter;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerAdapter;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
|
@ -866,6 +868,23 @@ class WebMvcAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlPathHelperDoesNotUseFullPathWithAdditionalDispatcherServlet() {
|
||||
this.contextRunner.withUserConfiguration(AdditionalDispatcherServletConfiguration.class).run((context) -> {
|
||||
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
||||
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(false);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlPathHelperDoesNotUseFullPathWithAdditionalUntypedDispatcherServlet() {
|
||||
this.contextRunner.withUserConfiguration(AdditionalUntypedDispatcherServletConfiguration.class)
|
||||
.run((context) -> {
|
||||
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
||||
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(false);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertCacheControl(AssertableWebApplicationContext context) {
|
||||
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
|
||||
assertThat(handlerMap).hasSize(2);
|
||||
|
|
@ -1248,4 +1267,24 @@ class WebMvcAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class AdditionalDispatcherServletConfiguration {
|
||||
|
||||
@Bean
|
||||
ServletRegistrationBean<DispatcherServlet> additionalDispatcherServlet() {
|
||||
return new ServletRegistrationBean<>(new DispatcherServlet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class AdditionalUntypedDispatcherServletConfiguration {
|
||||
|
||||
@Bean
|
||||
ServletRegistrationBean<?> additionalDispatcherServlet() {
|
||||
return new ServletRegistrationBean<>(new DispatcherServlet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue