mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Adapt to change in default strategy for URL path matching in Spring MVC
Closes gh-31547
This commit is contained in:
parent
f015095ca0
commit
7954f5e566
@ -37,7 +37,6 @@ import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
|
|||||||
import org.springframework.boot.actuate.endpoint.web.Link;
|
import org.springframework.boot.actuate.endpoint.web.Link;
|
||||||
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
||||||
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
|
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@ -64,8 +63,7 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
|
|||||||
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
||||||
CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
|
CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
|
||||||
EndpointLinksResolver linksResolver) {
|
EndpointLinksResolver linksResolver) {
|
||||||
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true,
|
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true);
|
||||||
WebMvcAutoConfiguration.pathPatternParser);
|
|
||||||
this.securityInterceptor = securityInterceptor;
|
this.securityInterceptor = securityInterceptor;
|
||||||
this.linksResolver = linksResolver;
|
this.linksResolver = linksResolver;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
@ -85,7 +84,7 @@ public class WebMvcEndpointManagementContextConfiguration {
|
|||||||
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
|
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
|
||||||
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
|
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
|
||||||
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
|
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
|
||||||
shouldRegisterLinksMapping, WebMvcAutoConfiguration.pathPatternParser);
|
shouldRegisterLinksMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
|
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
|
||||||
|
@ -55,6 +55,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||||
|
import org.springframework.web.util.pattern.PathPatternParser;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.hamcrest.Matchers.both;
|
import static org.hamcrest.Matchers.both;
|
||||||
@ -86,7 +87,7 @@ class WebMvcEndpointIntegrationTests {
|
|||||||
this.context.setServletContext(new MockServletContext());
|
this.context.setServletContext(new MockServletContext());
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
WebMvcEndpointHandlerMapping handlerMapping = this.context.getBean(WebMvcEndpointHandlerMapping.class);
|
WebMvcEndpointHandlerMapping handlerMapping = this.context.getBean(WebMvcEndpointHandlerMapping.class);
|
||||||
assertThat(handlerMapping.getPatternParser()).isEqualTo(WebMvcAutoConfiguration.pathPatternParser);
|
assertThat(handlerMapping.getPatternParser()).isInstanceOf(PathPatternParser.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -128,29 +128,11 @@ public abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappin
|
|||||||
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
|
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
|
||||||
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
||||||
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {
|
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {
|
||||||
this(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@code AbstractWebMvcEndpointHandlerMapping} that provides mappings
|
|
||||||
* for the operations of the given endpoints.
|
|
||||||
* @param endpointMapping the base mapping for all endpoints
|
|
||||||
* @param endpoints the web endpoints
|
|
||||||
* @param endpointMediaTypes media types consumed and produced by the endpoints
|
|
||||||
* @param corsConfiguration the CORS configuration for the endpoints or {@code null}
|
|
||||||
* @param shouldRegisterLinksMapping whether the links endpoint should be registered
|
|
||||||
* @param pathPatternParser the path pattern parser
|
|
||||||
*/
|
|
||||||
public AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,
|
|
||||||
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
|
|
||||||
CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping,
|
|
||||||
PathPatternParser pathPatternParser) {
|
|
||||||
this.endpointMapping = endpointMapping;
|
this.endpointMapping = endpointMapping;
|
||||||
this.endpoints = endpoints;
|
this.endpoints = endpoints;
|
||||||
this.endpointMediaTypes = endpointMediaTypes;
|
this.endpointMediaTypes = endpointMediaTypes;
|
||||||
this.corsConfiguration = corsConfiguration;
|
this.corsConfiguration = corsConfiguration;
|
||||||
this.shouldRegisterLinksMapping = shouldRegisterLinksMapping;
|
this.shouldRegisterLinksMapping = shouldRegisterLinksMapping;
|
||||||
setPatternParser(pathPatternParser);
|
|
||||||
setOrder(-100);
|
setOrder(-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ import org.springframework.boot.actuate.endpoint.web.Link;
|
|||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
import org.springframework.web.util.pattern.PathPatternParser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom {@link HandlerMapping} that makes web endpoints available over HTTP using
|
* A custom {@link HandlerMapping} that makes web endpoints available over HTTP using
|
||||||
@ -63,27 +62,6 @@ public class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerM
|
|||||||
setOrder(-100);
|
setOrder(-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@code WebMvcEndpointHandlerMapping} instance that provides mappings
|
|
||||||
* for the given endpoints.
|
|
||||||
* @param endpointMapping the base mapping for all endpoints
|
|
||||||
* @param endpoints the web endpoints
|
|
||||||
* @param endpointMediaTypes media types consumed and produced by the endpoints
|
|
||||||
* @param corsConfiguration the CORS configuration for the endpoints or {@code null}
|
|
||||||
* @param linksResolver resolver for determining links to available endpoints
|
|
||||||
* @param shouldRegisterLinksMapping whether the links endpoint should be registered
|
|
||||||
* @param pathPatternParser the path pattern parser
|
|
||||||
*/
|
|
||||||
public WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<ExposableWebEndpoint> endpoints,
|
|
||||||
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
|
|
||||||
EndpointLinksResolver linksResolver, boolean shouldRegisterLinksMapping,
|
|
||||||
PathPatternParser pathPatternParser) {
|
|
||||||
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping,
|
|
||||||
pathPatternParser);
|
|
||||||
this.linksResolver = linksResolver;
|
|
||||||
setOrder(-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LinksHandler getLinksHandler() {
|
protected LinksHandler getLinksHandler() {
|
||||||
return new WebMvcLinksHandler();
|
return new WebMvcLinksHandler();
|
||||||
|
@ -75,6 +75,7 @@ import org.springframework.format.FormatterRegistry;
|
|||||||
import org.springframework.format.support.FormattingConversionService;
|
import org.springframework.format.support.FormattingConversionService;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||||
import org.springframework.validation.MessageCodesResolver;
|
import org.springframework.validation.MessageCodesResolver;
|
||||||
@ -250,20 +251,20 @@ public class WebMvcAutoConfiguration {
|
|||||||
@Override
|
@Override
|
||||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||||
if (this.mvcProperties.getPathmatch()
|
if (this.mvcProperties.getPathmatch()
|
||||||
.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
|
.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.ANT_PATH_MATCHER) {
|
||||||
configurer.setPatternParser(pathPatternParser);
|
configurer.setPathMatcher(new AntPathMatcher());
|
||||||
|
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
|
||||||
|
configurer.setUseRegisteredSuffixPatternMatch(
|
||||||
|
this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
|
||||||
|
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
|
||||||
|
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
|
||||||
|
if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
|
||||||
|
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||||
|
urlPathHelper.setAlwaysUseFullPath(true);
|
||||||
|
configurer.setUrlPathHelper(urlPathHelper);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
|
|
||||||
configurer.setUseRegisteredSuffixPatternMatch(
|
|
||||||
this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
|
|
||||||
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
|
|
||||||
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
|
|
||||||
if (servletUrlMapping.equals("/") && singleDispatcherServlet()) {
|
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
urlPathHelper.setAlwaysUseFullPath(true);
|
|
||||||
configurer.setUrlPathHelper(urlPathHelper);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean singleDispatcherServlet() {
|
private boolean singleDispatcherServlet() {
|
||||||
|
@ -958,19 +958,21 @@ class WebMvcAutoConfigurationTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void urlPathHelperUsesFullPathByDefault() {
|
void urlPathHelperUsesFullPathByDefaultWhenAntPathMatchingIsUsed() {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.withPropertyValues("spring.mvc.pathmatch.matching-strategy:ant-path-matcher")
|
||||||
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
.run((context) -> {
|
||||||
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(true);
|
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
||||||
});
|
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void urlPathHelperDoesNotUseFullPathWithServletMapping() {
|
void urlPathHelperDoesNotUseFullPathWithServletMapping() {
|
||||||
this.contextRunner.withPropertyValues("spring.mvc.servlet.path=/test/").run((context) -> {
|
this.contextRunner.withPropertyValues("spring.mvc.pathmatch.matching-strategy:ant-path-matcher")
|
||||||
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
.withPropertyValues("spring.mvc.servlet.path=/test/").run((context) -> {
|
||||||
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(false);
|
UrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);
|
||||||
});
|
assertThat(urlPathHelper).extracting("alwaysUseFullPath").isEqualTo(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user