Merge pull request #1856 from dkapil/gh-1789

GH-1789 Added matchTrailingSlash parameter to use instead of matchOpt…
This commit is contained in:
Ryan Baxter
2020-07-27 10:50:59 -04:00
committed by GitHub
4 changed files with 53 additions and 17 deletions

View File

@@ -270,7 +270,7 @@ This route matches if the request method was a `GET` or a `POST`.
=== The Path Route Predicate Factory
The `Path` Route Predicate Factory takes two parameters: a list of Spring `PathMatcher` `patterns` and an optional flag called `matchOptionalTrailingSeparator`.
The `Path` Route Predicate Factory takes two parameters: a list of Spring `PathMatcher` `patterns` and an optional flag called `matchTrailingSlash` (defaults to `true`).
The following example configures a path route predicate:
.application.yml
@@ -288,7 +288,9 @@ spring:
----
====
This route matches if the request path was, for example: `/red/1` or `/red/blue` or `/blue/green`.
This route matches if the request path was, for example: `/red/1` or `/red/1/` or `/red/blue` or `/blue/green`.
If `matchTrailingSlash` is set to `false`, then request path `/red/1/` will not be matched.
This predicate extracts the URI template variables (such as `segment`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`.
Those values are then available for use by <<gateway-route-filters,`GatewayFilter` factories>>

View File

@@ -38,13 +38,14 @@ import static org.springframework.http.server.PathContainer.parsePath;
/**
* @author Spencer Gibb
* @author Dhawal Kapil
*/
public class PathRoutePredicateFactory
extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {
private static final Log log = LogFactory.getLog(RoutePredicateFactory.class);
private static final Log log = LogFactory.getLog(PathRoutePredicateFactory.class);
private static final String MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY = "matchOptionalTrailingSeparator";
private static final String MATCH_TRAILING_SLASH = "matchTrailingSlash";
private PathPatternParser pathPatternParser = new PathPatternParser();
@@ -67,7 +68,7 @@ public class PathRoutePredicateFactory
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("patterns", MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY);
return Arrays.asList("patterns", MATCH_TRAILING_SLASH);
}
@Override
@@ -79,8 +80,8 @@ public class PathRoutePredicateFactory
public Predicate<ServerWebExchange> apply(Config config) {
final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
synchronized (this.pathPatternParser) {
pathPatternParser.setMatchOptionalTrailingSeparator(
config.isMatchOptionalTrailingSeparator());
pathPatternParser
.setMatchOptionalTrailingSeparator(config.isMatchTrailingSlash());
config.getPatterns().forEach(pattern -> {
PathPattern pathPattern = this.pathPatternParser.parse(pattern);
pathPatterns.add(pathPattern);
@@ -111,7 +112,7 @@ public class PathRoutePredicateFactory
@Override
public String toString() {
return String.format("Paths: %s, match trailing slash: %b",
config.getPatterns(), config.isMatchOptionalTrailingSeparator());
config.getPatterns(), config.isMatchTrailingSlash());
}
};
}
@@ -121,7 +122,7 @@ public class PathRoutePredicateFactory
private List<String> patterns = new ArrayList<>();
private boolean matchOptionalTrailingSeparator = true;
private boolean matchTrailingSlash = true;
public List<String> getPatterns() {
return patterns;
@@ -132,22 +133,37 @@ public class PathRoutePredicateFactory
return this;
}
/**
* @deprecated use {@link #isMatchTrailingSlash()}
*/
@Deprecated
public boolean isMatchOptionalTrailingSeparator() {
return matchOptionalTrailingSeparator;
return isMatchTrailingSlash();
}
/**
* @deprecated use {@link #setMatchTrailingSlash(boolean)}
*/
@Deprecated
public Config setMatchOptionalTrailingSeparator(
boolean matchOptionalTrailingSeparator) {
this.matchOptionalTrailingSeparator = matchOptionalTrailingSeparator;
setMatchTrailingSlash(matchOptionalTrailingSeparator);
return this;
}
public boolean isMatchTrailingSlash() {
return matchTrailingSlash;
}
public Config setMatchTrailingSlash(boolean matchTrailingSlash) {
this.matchTrailingSlash = matchTrailingSlash;
return this;
}
@Override
public String toString() {
return new ToStringCreator(this).append("patterns", patterns)
.append("matchOptionalTrailingSeparator",
matchOptionalTrailingSeparator)
.toString();
.append(MATCH_TRAILING_SLASH, matchTrailingSlash).toString();
}
}

View File

@@ -185,14 +185,14 @@ public class PredicateSpec extends UriSpec {
* A predicate that checks if the path of the request matches the given pattern
* @param patterns the pattern to check the path against. The pattern is a
* {@link org.springframework.util.PathMatcher} pattern
* @param matchOptionalTrailingSeparator set to false if you do not want this path to
* @param matchTrailingSlash set to false if you do not want this path to
* match when there is a trailing <code>/</code>
* @return a {@link BooleanSpec} to be used to add logical operators
*/
public BooleanSpec path(boolean matchOptionalTrailingSeparator, String... patterns) {
public BooleanSpec path(boolean matchTrailingSlash, String... patterns) {
return asyncPredicate(getBean(PathRoutePredicateFactory.class).applyAsync(c -> c
.setPatterns(Arrays.asList(patterns))
.setMatchOptionalTrailingSeparator(matchOptionalTrailingSeparator)));
.setMatchTrailingSlash(matchTrailingSlash)));
}
/**

View File

@@ -36,6 +36,7 @@ import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.server.ServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@@ -98,6 +99,13 @@ public class PathRoutePredicateFactoryTests extends BaseWebClientTests {
.expectHeader().valueEquals(ROUTE_ID_HEADER, "path_test");
}
@Test
public void matchOptionalTrailingSeparatorCopiedToMatchTrailingSlash() {
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB"))
.setMatchOptionalTrailingSeparator(false);
assertThat(config.isMatchTrailingSlash()).isEqualTo(false);
}
@Test
public void toStringFormat() {
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB"))
@@ -107,6 +115,16 @@ public class PathRoutePredicateFactoryTests extends BaseWebClientTests {
.contains("false");
}
@Test
public void toStringFormatMatchTrailingSlashTrue() {
Config config = new Config().setPatterns(Arrays.asList("patternA", "patternB"))
.setMatchTrailingSlash(true);
Predicate<ServerWebExchange> predicate = new PathRoutePredicateFactory().apply(config);
assertThat(predicate.toString()).contains("patternA").contains("patternB")
.contains("true");
}
@EnableAutoConfiguration
@SpringBootConfiguration
@Import(DefaultTestConfig.class)