Enable use of parsed patterns by default in Spring MVC
Closes gh-28607
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -127,6 +127,8 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder<StandaloneM
|
||||
@Nullable
|
||||
private FlashMapManager flashMapManager;
|
||||
|
||||
private boolean preferPathMatcher = false;
|
||||
|
||||
@Nullable
|
||||
private PathPatternParser patternParser;
|
||||
|
||||
@@ -317,8 +319,10 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder<StandaloneM
|
||||
* @param parser the parser to use
|
||||
* @since 5.3
|
||||
*/
|
||||
public void setPatternParser(PathPatternParser parser) {
|
||||
public StandaloneMockMvcBuilder setPatternParser(@Nullable PathPatternParser parser) {
|
||||
this.patternParser = parser;
|
||||
this.preferPathMatcher = (this.patternParser == null);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,6 +336,7 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder<StandaloneM
|
||||
@Deprecated
|
||||
public StandaloneMockMvcBuilder setUseSuffixPatternMatch(boolean useSuffixPatternMatch) {
|
||||
this.useSuffixPatternMatch = useSuffixPatternMatch;
|
||||
this.preferPathMatcher |= useSuffixPatternMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -468,15 +473,16 @@ public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder<StandaloneM
|
||||
|
||||
RequestMappingHandlerMapping handlerMapping = handlerMappingFactory.get();
|
||||
handlerMapping.setEmbeddedValueResolver(new StaticStringValueResolver(placeholderValues));
|
||||
if (patternParser != null) {
|
||||
handlerMapping.setPatternParser(patternParser);
|
||||
}
|
||||
else {
|
||||
if (patternParser == null && preferPathMatcher) {
|
||||
handlerMapping.setPatternParser(null);
|
||||
handlerMapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
|
||||
if (removeSemicolonContent != null) {
|
||||
handlerMapping.setRemoveSemicolonContent(removeSemicolonContent);
|
||||
}
|
||||
}
|
||||
else if (patternParser != null) {
|
||||
handlerMapping.setPatternParser(patternParser);
|
||||
}
|
||||
handlerMapping.setUseTrailingSlashMatch(useTrailingSlashPatternMatch);
|
||||
handlerMapping.setOrder(0);
|
||||
handlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -53,7 +53,7 @@ import org.springframework.web.util.pattern.PathPatternParser;
|
||||
*/
|
||||
public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource {
|
||||
|
||||
private static PathMatcher defaultPathMatcher = new AntPathMatcher();
|
||||
private static final PathMatcher defaultPathMatcher = new AntPathMatcher();
|
||||
|
||||
|
||||
private final PathPatternParser patternParser;
|
||||
@@ -157,7 +157,7 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource
|
||||
* pattern matching with {@link PathMatcher} or with parsed {@link PathPattern}s.
|
||||
* <p>In Spring MVC, either a resolved String lookupPath or a parsed
|
||||
* {@code RequestPath} is always available within {@code DispatcherServlet}
|
||||
* processing. However in a Servlet {@code Filter} such as {@code CorsFilter}
|
||||
* processing. However, in a Servlet {@code Filter} such as {@code CorsFilter}
|
||||
* that may or may not be the case.
|
||||
* <p>By default this is set to {@code true} in which case lazy lookupPath
|
||||
* initialization is allowed. Set this to {@code false} when an
|
||||
|
||||
@@ -252,6 +252,9 @@ public abstract class ServletRequestPathUtils {
|
||||
if (UrlPathHelper.servlet4Present) {
|
||||
String servletPathPrefix = Servlet4Delegate.getServletPathPrefix(request);
|
||||
if (StringUtils.hasText(servletPathPrefix)) {
|
||||
if (servletPathPrefix.endsWith("/")) {
|
||||
servletPathPrefix = servletPathPrefix.substring(0, servletPathPrefix.length() - 1);
|
||||
}
|
||||
return new ServletRequestPath(requestUri, request.getContextPath(), servletPathPrefix);
|
||||
}
|
||||
}
|
||||
@@ -272,8 +275,7 @@ public abstract class ServletRequestPathUtils {
|
||||
if (mapping == null) {
|
||||
mapping = request.getHttpServletMapping();
|
||||
}
|
||||
MappingMatch match = mapping.getMappingMatch();
|
||||
if (!ObjectUtils.nullSafeEquals(match, MappingMatch.PATH)) {
|
||||
if (!ObjectUtils.nullSafeEquals(mapping.getMappingMatch(), MappingMatch.PATH)) {
|
||||
return null;
|
||||
}
|
||||
String servletPath = (String) request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -405,22 +405,28 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (pathMatchingElement != null) {
|
||||
Object source = context.extractSource(element);
|
||||
|
||||
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
|
||||
Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
|
||||
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("trailing-slash")) {
|
||||
Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
|
||||
boolean useTrailingSlashMatch = Boolean.parseBoolean(pathMatchingElement.getAttribute("trailing-slash"));
|
||||
handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
|
||||
}
|
||||
|
||||
boolean preferPathMatcher = false;
|
||||
|
||||
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
|
||||
boolean useSuffixPatternMatch = Boolean.parseBoolean(pathMatchingElement.getAttribute("suffix-pattern"));
|
||||
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
|
||||
preferPathMatcher |= useSuffixPatternMatch;
|
||||
}
|
||||
if (pathMatchingElement.hasAttribute("registered-suffixes-only")) {
|
||||
Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only"));
|
||||
boolean useRegisteredSuffixPatternMatch = Boolean.parseBoolean(pathMatchingElement.getAttribute("registered-suffixes-only"));
|
||||
handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch);
|
||||
preferPathMatcher |= useRegisteredSuffixPatternMatch;
|
||||
}
|
||||
|
||||
RuntimeBeanReference pathHelperRef = null;
|
||||
if (pathMatchingElement.hasAttribute("path-helper")) {
|
||||
pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
|
||||
preferPathMatcher = true;
|
||||
}
|
||||
pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, context, source);
|
||||
handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);
|
||||
@@ -428,10 +434,16 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
RuntimeBeanReference pathMatcherRef = null;
|
||||
if (pathMatchingElement.hasAttribute("path-matcher")) {
|
||||
pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
|
||||
preferPathMatcher = true;
|
||||
}
|
||||
pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
|
||||
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
|
||||
|
||||
if (preferPathMatcher) {
|
||||
handlerMappingDef.getPropertyValues().add("patternParser", null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Properties getDefaultMediaTypes() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -23,7 +23,6 @@ import java.util.function.Predicate;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
@@ -34,14 +33,19 @@ import org.springframework.web.util.pattern.PathPatternParser;
|
||||
* <ul>
|
||||
* <li>{@link WebMvcConfigurationSupport#requestMappingHandlerMapping}</li>
|
||||
* <li>{@link WebMvcConfigurationSupport#viewControllerHandlerMapping}</li>
|
||||
* <li>{@link WebMvcConfigurationSupport#beanNameHandlerMapping}</li>
|
||||
* <li>{@link WebMvcConfigurationSupport#routerFunctionMapping}</li>
|
||||
* <li>{@link WebMvcConfigurationSupport#resourceHandlerMapping}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public class PathMatchConfigurer {
|
||||
|
||||
private boolean preferPathMatcher = false;
|
||||
|
||||
@Nullable
|
||||
private PathPatternParser patternParser;
|
||||
|
||||
@@ -74,17 +78,28 @@ public class PathMatchConfigurer {
|
||||
|
||||
|
||||
/**
|
||||
* Enable use of parsed {@link PathPattern}s as described in
|
||||
* {@link AbstractHandlerMapping#setPatternParser(PathPatternParser)}.
|
||||
* <p><strong>Note:</strong> This is mutually exclusive with use of
|
||||
* {@link #setUrlPathHelper(UrlPathHelper)} and
|
||||
* {@link #setPathMatcher(PathMatcher)}.
|
||||
* <p>By default this is not enabled.
|
||||
* Set the {@link PathPatternParser} to parse {@link PathPattern patterns}
|
||||
* with for URL path matching. Parsed patterns provide a more modern and
|
||||
* efficient alternative to String path matching via {@link AntPathMatcher}.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with the
|
||||
* following other, {@code AntPathMatcher} related properties:
|
||||
* <ul>
|
||||
* <li>{@link #setUseSuffixPatternMatch(Boolean)}
|
||||
* <li>{@link #setUseRegisteredSuffixPatternMatch(Boolean)}
|
||||
* <li>{@link #setUrlPathHelper(UrlPathHelper)}
|
||||
* <li>{@link #setPathMatcher(PathMatcher)}
|
||||
* </ul>
|
||||
* <p>By default, as of 6.0, a {@link PathPatternParser} with default
|
||||
* settings is used, which enables parsed {@link PathPattern patterns}.
|
||||
* Set this property to {@code null} to fall back on String path matching via
|
||||
* {@link AntPathMatcher} instead, or alternatively, setting one of the above
|
||||
* listed {@code AntPathMatcher} related properties has the same effect.
|
||||
* @param patternParser the parser to pre-parse patterns with
|
||||
* @since 5.3
|
||||
*/
|
||||
public PathMatchConfigurer setPatternParser(PathPatternParser patternParser) {
|
||||
public PathMatchConfigurer setPatternParser(@Nullable PathPatternParser patternParser) {
|
||||
this.patternParser = patternParser;
|
||||
this.preferPathMatcher = (patternParser == null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -120,9 +135,11 @@ public class PathMatchConfigurer {
|
||||
/**
|
||||
* Whether to use suffix pattern match (".*") when matching patterns to
|
||||
* requests. If enabled a method mapped to "/users" also matches to "/users.*".
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with
|
||||
* {@link #setPatternParser(PathPatternParser)}. If set, it enables use of
|
||||
* String path matching, unless a {@code PathPatternParser} is also
|
||||
* explicitly set in which case this property is ignored.
|
||||
* <p>By default this is set to {@code false}.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with and
|
||||
* ignored when {@link #setPatternParser(PathPatternParser)} is set.
|
||||
* @deprecated as of 5.2.4. See class-level note in
|
||||
* {@link RequestMappingHandlerMapping} on the deprecation of path extension
|
||||
* config options. As there is no replacement for this method, in 5.2.x it is
|
||||
@@ -132,6 +149,7 @@ public class PathMatchConfigurer {
|
||||
@Deprecated
|
||||
public PathMatchConfigurer setUseSuffixPatternMatch(Boolean suffixPatternMatch) {
|
||||
this.suffixPatternMatch = suffixPatternMatch;
|
||||
this.preferPathMatcher |= suffixPatternMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -141,9 +159,11 @@ public class PathMatchConfigurer {
|
||||
* {@link WebMvcConfigurer#configureContentNegotiation configure content
|
||||
* negotiation}. This is generally recommended to reduce ambiguity and to
|
||||
* avoid issues such as when a "." appears in the path for other reasons.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with
|
||||
* {@link #setPatternParser(PathPatternParser)}. If set, it enables use of
|
||||
* String path matching, unless a {@code PathPatternParser} is also
|
||||
* explicitly set in which case this property is ignored.
|
||||
* <p>By default this is set to "false".
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with and
|
||||
* ignored when {@link #setPatternParser(PathPatternParser)} is set.
|
||||
* @deprecated as of 5.2.4. See class-level note in
|
||||
* {@link RequestMappingHandlerMapping} on the deprecation of path extension
|
||||
* config options.
|
||||
@@ -151,31 +171,54 @@ public class PathMatchConfigurer {
|
||||
@Deprecated
|
||||
public PathMatchConfigurer setUseRegisteredSuffixPatternMatch(Boolean registeredSuffixPatternMatch) {
|
||||
this.registeredSuffixPatternMatch = registeredSuffixPatternMatch;
|
||||
this.preferPathMatcher |= registeredSuffixPatternMatch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the UrlPathHelper to use to resolve the mapping path for the application.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with and
|
||||
* ignored when {@link #setPatternParser(PathPatternParser)} is set.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with
|
||||
* {@link #setPatternParser(PathPatternParser)}. If set, it enables use of
|
||||
* String path matching, unless a {@code PathPatternParser} is also
|
||||
* explicitly set in which case this property is ignored.
|
||||
* <p>By default this is an instance of {@link UrlPathHelper} with default
|
||||
* settings.
|
||||
*/
|
||||
public PathMatchConfigurer setUrlPathHelper(UrlPathHelper urlPathHelper) {
|
||||
this.urlPathHelper = urlPathHelper;
|
||||
this.preferPathMatcher = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PathMatcher to use for String pattern matching.
|
||||
* <p>By default this is {@link AntPathMatcher}.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with and
|
||||
* ignored when {@link #setPatternParser(PathPatternParser)} is set.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with
|
||||
* {@link #setPatternParser(PathPatternParser)}. If set, it enables use of
|
||||
* String path matching, unless a {@code PathPatternParser} is also
|
||||
* explicitly set in which case this property is ignored.
|
||||
* <p>By default this is an instance of {@link AntPathMatcher} with default
|
||||
* settings.
|
||||
*/
|
||||
public PathMatchConfigurer setPathMatcher(PathMatcher pathMatcher) {
|
||||
this.pathMatcher = pathMatcher;
|
||||
this.preferPathMatcher = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether to prefer {@link PathMatcher}. This is the case when either is true:
|
||||
* <ul>
|
||||
* <li>{@link PathPatternParser} is explicitly set to {@code null}.
|
||||
* <li>{@link PathPatternParser} is not explicitly set, and a
|
||||
* {@link PathMatcher} related option is explicitly set.
|
||||
* </ul>
|
||||
* @since 6.0
|
||||
*/
|
||||
protected boolean preferPathMatcher() {
|
||||
return (this.patternParser == null && this.preferPathMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link PathPatternParser} to use, if configured.
|
||||
* @since 5.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -313,18 +313,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
|
||||
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
|
||||
mapping.setOrder(0);
|
||||
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
|
||||
mapping.setContentNegotiationManager(contentNegotiationManager);
|
||||
mapping.setCorsConfigurations(getCorsConfigurations());
|
||||
|
||||
initHandlerMapping(mapping, conversionService, resourceUrlProvider);
|
||||
|
||||
PathMatchConfigurer pathConfig = getPathMatchConfigurer();
|
||||
if (pathConfig.getPatternParser() != null) {
|
||||
mapping.setPatternParser(pathConfig.getPatternParser());
|
||||
}
|
||||
else {
|
||||
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
|
||||
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
|
||||
|
||||
if (pathConfig.preferPathMatcher()) {
|
||||
Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
|
||||
if (useSuffixPatternMatch != null) {
|
||||
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
|
||||
@@ -334,10 +328,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
|
||||
}
|
||||
}
|
||||
|
||||
Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
|
||||
if (useTrailingSlashMatch != null) {
|
||||
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
|
||||
}
|
||||
|
||||
if (pathConfig.getPathPrefixes() != null) {
|
||||
mapping.setPathPrefixes(pathConfig.getPathPrefixes());
|
||||
}
|
||||
@@ -497,21 +493,29 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
|
||||
addViewControllers(registry);
|
||||
|
||||
AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
|
||||
if (handlerMapping == null) {
|
||||
return null;
|
||||
AbstractHandlerMapping mapping = registry.buildHandlerMapping();
|
||||
initHandlerMapping(mapping, conversionService, resourceUrlProvider);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private void initHandlerMapping(
|
||||
@Nullable AbstractHandlerMapping mapping, FormattingConversionService conversionService,
|
||||
ResourceUrlProvider resourceUrlProvider) {
|
||||
|
||||
if (mapping == null) {
|
||||
return;
|
||||
}
|
||||
PathMatchConfigurer pathConfig = getPathMatchConfigurer();
|
||||
if (pathConfig.getPatternParser() != null) {
|
||||
handlerMapping.setPatternParser(pathConfig.getPatternParser());
|
||||
if (pathConfig.preferPathMatcher()) {
|
||||
mapping.setPatternParser(null);
|
||||
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
|
||||
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
|
||||
}
|
||||
else {
|
||||
handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
|
||||
handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
|
||||
else if (pathConfig.getPatternParser() != null) {
|
||||
mapping.setPatternParser(pathConfig.getPatternParser());
|
||||
}
|
||||
handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
|
||||
handlerMapping.setCorsConfigurations(getCorsConfigurations());
|
||||
return handlerMapping;
|
||||
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
|
||||
mapping.setCorsConfigurations(getCorsConfigurations());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,18 +536,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
|
||||
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
|
||||
mapping.setOrder(2);
|
||||
|
||||
PathMatchConfigurer pathConfig = getPathMatchConfigurer();
|
||||
if (pathConfig.getPatternParser() != null) {
|
||||
mapping.setPatternParser(pathConfig.getPatternParser());
|
||||
}
|
||||
else {
|
||||
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
|
||||
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
|
||||
}
|
||||
|
||||
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
|
||||
mapping.setCorsConfigurations(getCorsConfigurations());
|
||||
initHandlerMapping(mapping, conversionService, resourceUrlProvider);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@@ -599,20 +592,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
|
||||
addResourceHandlers(registry);
|
||||
|
||||
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
|
||||
if (handlerMapping == null) {
|
||||
return null;
|
||||
}
|
||||
if (pathConfig.getPatternParser() != null) {
|
||||
handlerMapping.setPatternParser(pathConfig.getPatternParser());
|
||||
}
|
||||
else {
|
||||
handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
|
||||
handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
|
||||
}
|
||||
handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
|
||||
handlerMapping.setCorsConfigurations(getCorsConfigurations());
|
||||
return handlerMapping;
|
||||
AbstractHandlerMapping mapping = registry.getHandlerMapping();
|
||||
initHandlerMapping(mapping, conversionService, resourceUrlProvider);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -49,6 +49,7 @@ import org.springframework.web.cors.CorsProcessor;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
import org.springframework.web.cors.DefaultCorsProcessor;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
@@ -87,7 +88,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
private Object defaultHandler;
|
||||
|
||||
@Nullable
|
||||
private PathPatternParser patternParser;
|
||||
private PathPatternParser patternParser = new PathPatternParser();
|
||||
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
@@ -127,43 +128,45 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable use of pre-parsed {@link PathPattern}s as an alternative to
|
||||
* String pattern matching with {@link AntPathMatcher}. The syntax is
|
||||
* largely the same but the {@code PathPattern} syntax is more tailored for
|
||||
* web applications, and its implementation is more efficient.
|
||||
* <p>This property is mutually exclusive with the following others which
|
||||
* are effectively ignored when this is set:
|
||||
* Set the {@link PathPatternParser} to parse {@link PathPattern patterns}
|
||||
* with for URL path matching. Parsed patterns provide a more modern and
|
||||
* efficient alternative to String path matching via {@link AntPathMatcher}.
|
||||
* <p><strong>Note:</strong> This property is mutually exclusive with the
|
||||
* below properties, all of which are not necessary for parsed patterns and
|
||||
* are ignored when a {@code PathPatternParser} is available:
|
||||
* <ul>
|
||||
* <li>{@link #setAlwaysUseFullPath} -- {@code PathPatterns} always use the
|
||||
* full path and ignore the servletPath/pathInfo which are decoded and
|
||||
* partially normalized and therefore not comparable against the
|
||||
* {@link HttpServletRequest#getRequestURI() requestURI}.
|
||||
* <li>{@link #setRemoveSemicolonContent} -- {@code PathPatterns} always
|
||||
* <li>{@link #setAlwaysUseFullPath} -- parsed patterns always use the
|
||||
* full path and consider the servletPath only when a Servlet is mapped by
|
||||
* path prefix.
|
||||
* <li>{@link #setRemoveSemicolonContent} -- parsed patterns always
|
||||
* ignore semicolon content for path matching purposes, but path parameters
|
||||
* remain available for use in controllers via {@code @MatrixVariable}.
|
||||
* <li>{@link #setUrlDecode} -- {@code PathPatterns} match one decoded path
|
||||
* segment at a time and never need the full decoded path which can cause
|
||||
* issues due to decoded reserved characters.
|
||||
* <li>{@link #setUrlPathHelper} -- the request path is pre-parsed globally
|
||||
* by the {@link org.springframework.web.servlet.DispatcherServlet
|
||||
* DispatcherServlet} or by
|
||||
* <li>{@link #setUrlDecode} -- parsed patterns match one decoded path
|
||||
* segment at a time and therefore don't need to decode the full path.
|
||||
* <li>{@link #setUrlPathHelper} -- for parsed patterns, the request path
|
||||
* is parsed once in {@link org.springframework.web.servlet.DispatcherServlet
|
||||
* DispatcherServlet} or in
|
||||
* {@link org.springframework.web.filter.ServletRequestPathFilter
|
||||
* ServletRequestPathFilter} using {@link ServletRequestPathUtils} and saved
|
||||
* in a request attribute for re-use.
|
||||
* <li>{@link #setPathMatcher} -- patterns are parsed to {@code PathPatterns}
|
||||
* and used instead of String matching with {@code PathMatcher}.
|
||||
* ServletRequestPathFilter} using {@link ServletRequestPathUtils} and cached
|
||||
* in a request attribute.
|
||||
* <li>{@link #setPathMatcher} -- a parsed patterns encapsulates the logic
|
||||
* for path matching and does need a {@code PathMatcher}.
|
||||
* </ul>
|
||||
* <p>By default this is not set.
|
||||
* <p>By default, as of 6.0, this is set to a {@link PathPatternParser}
|
||||
* instance with default settings and therefore use of parsed patterns is
|
||||
* enabled. Set this to {@code null} to switch to String path matching
|
||||
* via {@link AntPathMatcher} instead.
|
||||
* @param patternParser the parser to use
|
||||
* @since 5.3
|
||||
*/
|
||||
public void setPatternParser(PathPatternParser patternParser) {
|
||||
public void setPatternParser(@Nullable PathPatternParser patternParser) {
|
||||
this.patternParser = patternParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link #setPatternParser(PathPatternParser) configured}
|
||||
* {@code PathPatternParser}, or {@code null}.
|
||||
* {@code PathPatternParser}, or {@code null} otherwise which indicates that
|
||||
* String pattern matching with {@link AntPathMatcher} is enabled instead.
|
||||
* @since 5.3
|
||||
*/
|
||||
@Nullable
|
||||
@@ -570,7 +573,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
protected String initLookupPath(HttpServletRequest request) {
|
||||
if (usesPathPatterns()) {
|
||||
request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
|
||||
RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
|
||||
RequestPath requestPath = getRequestPath(request);
|
||||
String lookupPath = requestPath.pathWithinApplication().value();
|
||||
return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
|
||||
}
|
||||
@@ -579,6 +582,14 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
}
|
||||
}
|
||||
|
||||
private RequestPath getRequestPath(HttpServletRequest request) {
|
||||
// Expect pre-parsed path with DispatcherServlet,
|
||||
// but otherwise parse per handler lookup + cache for handling
|
||||
return request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null ?
|
||||
ServletRequestPathUtils.getParsedRequestPath(request) :
|
||||
ServletRequestPathUtils.parseAndCache(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link HandlerExecutionChain} for the given handler, including
|
||||
* applicable interceptors.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -102,7 +102,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
|
||||
|
||||
@Override
|
||||
public void setPatternParser(PathPatternParser patternParser) {
|
||||
public void setPatternParser(@Nullable PathPatternParser patternParser) {
|
||||
Assert.state(this.mappingRegistry.getRegistrations().isEmpty(),
|
||||
"PathPatternParser must be set before the initialization of " +
|
||||
"request mappings through InitializingBean#afterPropertiesSet.");
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
|
||||
|
||||
|
||||
@Override
|
||||
public void setPatternParser(PathPatternParser patternParser) {
|
||||
public void setPatternParser(@Nullable PathPatternParser patternParser) {
|
||||
Assert.state(this.handlerMap.isEmpty(),
|
||||
"PathPatternParser must be set before the initialization of " +
|
||||
"the handler map via ApplicationContextAware#setApplicationContext.");
|
||||
|
||||
@@ -76,6 +76,8 @@ import org.springframework.web.util.pattern.PathPatternParser;
|
||||
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
|
||||
implements MatchableHandlerMapping, EmbeddedValueResolverAware {
|
||||
|
||||
private boolean defaultPatternParser = true;
|
||||
|
||||
private boolean useSuffixPatternMatch = false;
|
||||
|
||||
private boolean useRegisteredSuffixPatternMatch = false;
|
||||
@@ -92,6 +94,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();
|
||||
|
||||
|
||||
@Override
|
||||
public void setPatternParser(@Nullable PathPatternParser patternParser) {
|
||||
if (patternParser != null) {
|
||||
this.defaultPatternParser = false;
|
||||
}
|
||||
super.setPatternParser(patternParser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to use suffix pattern match (".*") when matching patterns to
|
||||
* requests. If enabled a method mapped to "/users" also matches to "/users.*".
|
||||
@@ -191,6 +201,12 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
this.config.setTrailingSlashMatch(useTrailingSlashMatch());
|
||||
this.config.setContentNegotiationManager(getContentNegotiationManager());
|
||||
|
||||
if (getPatternParser() != null && this.defaultPatternParser &&
|
||||
(this.useSuffixPatternMatch || this.useRegisteredSuffixPatternMatch)) {
|
||||
|
||||
setPatternParser(null);
|
||||
}
|
||||
|
||||
if (getPatternParser() != null) {
|
||||
this.config.setPatternParser(getPatternParser());
|
||||
Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.MappingMatch;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -137,6 +138,7 @@ import org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer;
|
||||
import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;
|
||||
import org.springframework.web.servlet.view.script.ScriptTemplateConfigurer;
|
||||
import org.springframework.web.servlet.view.script.ScriptTemplateViewResolver;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletMapping;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
|
||||
import org.springframework.web.testfixture.servlet.MockRequestDispatcher;
|
||||
@@ -688,6 +690,7 @@ public class MvcNamespaceTests {
|
||||
request.setRequestURI("/myapp/app/");
|
||||
request.setContextPath("/myapp");
|
||||
request.setServletPath("/app/");
|
||||
request.setHttpServletMapping(new MockHttpServletMapping("", "", "", MappingMatch.PATH));
|
||||
chain = mapping2.getHandler(request);
|
||||
assertThat(chain.getInterceptorList().size()).isEqualTo(4);
|
||||
assertThat(chain.getInterceptorList().get(1) instanceof ConversionServiceExposingInterceptor).isTrue();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -181,6 +181,7 @@ public class DelegatingWebMvcConfigurationIntegrationTests {
|
||||
this.context = webContext;
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ViewControllerConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@@ -188,8 +189,16 @@ public class DelegatingWebMvcConfigurationIntegrationTests {
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
// tests need to check the "mvcPathMatcher" and "mvcUrlPathHelper" instances
|
||||
configurer.setPatternParser(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ResourceHandlerConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@@ -197,5 +206,13 @@ public class DelegatingWebMvcConfigurationIntegrationTests {
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
// tests need to check the "mvcPathMatcher" and "mvcUrlPathHelper" instances
|
||||
configurer.setPatternParser(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -37,8 +37,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
*/
|
||||
public class BeanNameUrlHandlerMappingTests {
|
||||
|
||||
public static final String CONF = "/org/springframework/web/servlet/handler/map1.xml";
|
||||
|
||||
private ConfigurableWebApplicationContext wac;
|
||||
|
||||
|
||||
@@ -47,7 +45,7 @@ public class BeanNameUrlHandlerMappingTests {
|
||||
MockServletContext sc = new MockServletContext("");
|
||||
wac = new XmlWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.setConfigLocations(new String[] {CONF});
|
||||
wac.setConfigLocations("/org/springframework/web/servlet/handler/map1.xml");
|
||||
wac.refresh();
|
||||
}
|
||||
|
||||
@@ -55,7 +53,7 @@ public class BeanNameUrlHandlerMappingTests {
|
||||
public void requestsWithoutHandlers() throws Exception {
|
||||
HandlerMapping hm = (HandlerMapping) wac.getBean("handlerMapping");
|
||||
|
||||
MockHttpServletRequest req = new MockHttpServletRequest("GET", "/mypath/nonsense.html");
|
||||
MockHttpServletRequest req = new MockHttpServletRequest("GET", "/myapp/mypath/nonsense.html");
|
||||
req.setContextPath("/myapp");
|
||||
Object h = hm.getHandler(req);
|
||||
assertThat(h == null).as("Handler is null").isTrue();
|
||||
@@ -121,6 +119,7 @@ public class BeanNameUrlHandlerMappingTests {
|
||||
@Test
|
||||
public void requestsWithFullPaths() throws Exception {
|
||||
BeanNameUrlHandlerMapping hm = new BeanNameUrlHandlerMapping();
|
||||
hm.setPatternParser(null); // the test targets AntPathPatcher-specific feature
|
||||
hm.setAlwaysUseFullPath(true);
|
||||
hm.setApplicationContext(wac);
|
||||
Object bean = wac.getBean("godCtrl");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -29,7 +29,6 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||
import org.springframework.web.testfixture.servlet.MockServletConfig;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -97,9 +96,8 @@ public abstract class AbstractServletHandlerMethodTests {
|
||||
}
|
||||
|
||||
BeanDefinition mappingDef = wac.getBeanDefinition("handlerMapping");
|
||||
if (usePathPatterns && !mappingDef.hasAttribute("patternParser")) {
|
||||
BeanDefinition parserDef = register("parser", PathPatternParser.class, wac);
|
||||
mappingDef.getPropertyValues().add("patternParser", parserDef);
|
||||
if (!usePathPatterns) {
|
||||
mappingDef.getPropertyValues().add("patternParser", null);
|
||||
}
|
||||
|
||||
register("handlerAdapter", RequestMappingHandlerAdapter.class, wac);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</bean>
|
||||
|
||||
<bean id="urlMapping2" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
|
||||
<property name="patternParser"><null/></property>
|
||||
<property name="urlDecode"><value>true</value></property>
|
||||
<property name="mappings"><ref bean="mappings"/></property>
|
||||
</bean>
|
||||
|
||||
@@ -580,8 +580,8 @@ initialization parameters (`init-param` elements) to the Servlet declaration in
|
||||
The Servlet API exposes the full request path as `requestURI` and further sub-divides it
|
||||
into `contextPath`, `servletPath`, and `pathInfo` whose values vary depending on how a
|
||||
Servlet is mapped. From these inputs, Spring MVC needs to determine the lookup path to
|
||||
use for handler mapping, which is the path within the mapping of the `DispatcherServlet`
|
||||
itself, excluding the `contextPath` and any `servletMapping` prefix, if present.
|
||||
use for mapping handlers, which should exclude the `contextPath` and any `servletMapping`
|
||||
prefix, if applicable.
|
||||
|
||||
The `servletPath` and `pathInfo` are decoded and that makes them impossible to compare
|
||||
directly to the full `requestURI` in order to derive the lookupPath and that makes it
|
||||
@@ -611,15 +611,17 @@ encoded path which may not always work well. Furthermore, sometimes the
|
||||
`DispatcherServlet` needs to share the URL space with another Servlet and may need to
|
||||
be mapped by prefix.
|
||||
|
||||
The above issues can be addressed more comprehensively by switching from `PathMatcher` to
|
||||
the parsed `PathPattern` available in 5.3 or higher, see
|
||||
<<mvc-ann-requestmapping-pattern-comparison>>. Unlike `AntPathMatcher` which needs
|
||||
either the lookup path decoded or the controller mapping encoded, a parsed `PathPattern`
|
||||
matches to a parsed representation of the path called `RequestPath`, one path segment
|
||||
at a time. This allows decoding and sanitizing path segment values individually without
|
||||
the risk of altering the structure of the path. Parsed `PathPattern` also supports
|
||||
the use of `servletPath` prefix mapping as long as the prefix is kept simple and does
|
||||
not have any characters that need to be encoded.
|
||||
The above issues are addressed when using `PathPatternParser` and parsed patterns, as
|
||||
an alternative to String path matching with `AntPathMatcher`. The `PathPatternParser` has
|
||||
been available for use in Spring MVC from version 5.3, and is enabled by default from
|
||||
version 6.0. Unlike `AntPathMatcher` which needs either the lookup path decoded or the
|
||||
controller mapping encoded, a parsed `PathPattern` matches to a parsed representation
|
||||
of the path called `RequestPath`, one path segment at a time. This allows decoding and
|
||||
sanitizing path segment values individually without the risk of altering the structure
|
||||
of the path. Parsed `PathPattern` also supports the use of `servletPath` prefix mapping
|
||||
as long as a Servlet path mapping is used and the prefix is kept simple, i.e. it has no
|
||||
encoded characters. For pattern syntax details and comparison, see
|
||||
<<mvc-ann-requestmapping-pattern-comparison>>.
|
||||
|
||||
|
||||
|
||||
@@ -1617,11 +1619,11 @@ filesystem, and other locations. It is less efficient and the String path input
|
||||
challenge for dealing effectively with encoding and other issues with URLs.
|
||||
|
||||
`PathPattern` is the recommended solution for web applications and it is the only choice in
|
||||
Spring WebFlux. Prior to version 5.3, `AntPathMatcher` was the only choice in Spring MVC
|
||||
and continues to be the default. However `PathPattern` can be enabled in the
|
||||
<<mvc-config-path-matching, MVC config>>.
|
||||
Spring WebFlux. It was enabled for use in Spring MVC from version 5.3 and is enabled by
|
||||
default from version 6.0. See <<mvc-config-path-matching, MVC config>> for
|
||||
customizations of path matching options.
|
||||
|
||||
`PathPattern` supports the same pattern syntax as `AntPathMatcher`. In addition it also
|
||||
`PathPattern` supports the same pattern syntax as `AntPathMatcher`. In addition, it also
|
||||
supports the capturing pattern, e.g. `+{*spring}+`, for matching 0 or more path segments
|
||||
at the end of a path. `PathPattern` also restricts the use of `+**+` for matching multiple
|
||||
path segments such that it's only allowed at the end of a pattern. This eliminates many
|
||||
@@ -5997,9 +5999,7 @@ The following example shows how to customize path matching in Java configuration
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
configurer
|
||||
.setPatternParser(new PathPatternParser())
|
||||
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
|
||||
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
|
||||
}
|
||||
|
||||
private PathPatternParser patternParser() {
|
||||
@@ -6015,9 +6015,7 @@ The following example shows how to customize path matching in Java configuration
|
||||
class WebConfig : WebMvcConfigurer {
|
||||
|
||||
override fun configurePathMatch(configurer: PathMatchConfigurer) {
|
||||
configurer
|
||||
.setPatternParser(patternParser)
|
||||
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
|
||||
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
|
||||
}
|
||||
|
||||
fun patternParser(): PathPatternParser {
|
||||
@@ -6026,7 +6024,7 @@ The following example shows how to customize path matching in Java configuration
|
||||
}
|
||||
----
|
||||
|
||||
The following example shows how to achieve the same configuration in XML:
|
||||
The following example shows how to customize path matching in XML configuration:
|
||||
|
||||
[source,xml,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
|
||||
Reference in New Issue
Block a user