Изучение соответствия URL-адресов в Spring 5 WebFlux
1. обзор
Spring 5 принесa newPathPatternParser для разбора шаблонов шаблонов URI.. Это альтернатива ранее использовавшемусяAntPathMatcher.
AntPathMatcher был реализацией сопоставления пути в стиле Ant. PathPatternParser разбивает путь на связанный списокPathElements. Эта цепочкаPathElements используется классомPathPattern для быстрого сопоставления шаблонов.
СPathPatternParser также была введена поддержка нового синтаксиса переменной URI.
В этой статьеwe’ll go through the new/updated URL pattern matchers introduced in Spring 5.0 WebFlux, а также те, которые использовались со времен более старых версий Spring.
2. Новые средства сопоставления шаблонов URL в Spring 5.0
Релиз Spring 5.0 добавил очень простой в использовании синтаксис переменной URI: \ {* foo} для захвата любого количества сегментов пути в конце шаблона.
2.1. Синтаксис переменной URI \ {* foo} Использование метода обработчика
Давайте посмотрим на пример шаблона переменной URI\{*foo}, другой пример с использованием@GetMapping и метода обработчика. Все, что мы укажем в пути после“/spring5”, будет сохранено в переменной пути «id»:
@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
return id;
}
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable() {
client.get()
.uri("/spring5/example/tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/example/tutorial");
client.get()
.uri("/spring5/example")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/example");
}
2.2. Синтаксис переменной URI \ {* foo} ИспользованиеRouterFunction
Давайте посмотрим на пример нового шаблона пути к переменной URI с использованиемRouterFunction:
private RouterFunction routingFunction() {
return route(GET("/test/{*id}"),
serverRequest -> ok().body(fromObject(serverRequest.pathVariable("id"))));
}
В этом случае любой путь, который мы напишем после «/ test», будет записан в переменной пути «id». Таким образом, контрольный пример для этого может быть:
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
throws Exception {
client.get()
.uri("/test/ab/cd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/ab/cd");
}
2.3. Использование синтаксиса переменной URI \ {* foo} для доступа к ресурсам
Если мы хотим получить доступ к ресурсам, нам нужно будет написать шаблон пути, аналогичный тому, который мы написали в предыдущем примере.
Допустим, наш шаблон:“/files/\{*filepaths}”.. В этом случае, если путь равен/files/hello.txt,, значение переменной пути“filepaths” будет «/hello.txt», тогда как, если путь равен /files/test/test.txt, значение“filepaths” = «/test/test.txt».
Наша функция маршрутизации для доступа к файловым ресурсам в каталоге/files/:
private RouterFunction routingFunction() {
return RouterFunctions.resources(
"/files/{*filepaths}",
new ClassPathResource("files/")));
}
Предположим, что наши текстовые файлыhello.txt иtest.txt содержат“hello” и“test” соответственно. Это можно продемонстрировать с помощью тестового примера JUnit:
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
throws Exception {
client.get()
.uri("/files/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
3. Существующие шаблоны URL из предыдущих версий
Давайте теперь взглянем на все другие сопоставители шаблонов URL, которые поддерживались более старыми версиями Spring. Все эти шаблоны работают как сRouterFunction, так и с методами Handler с@GetMapping.
3.1. '?' Соответствует ровно одному символу
Если мы укажем шаблон пути как:“/t?st _ “, _ это будет соответствовать таким путям, как:“/test” и“/tast”,, но не“/tst” и“/teest”.
Пример кода с использованиемRouterFunction и его тестового примера JUnit:
private RouterFunction routingFunction() {
return route(GET("/t?st"),
serverRequest -> ok().body(fromObject("Path /t?st is accessed")));
}
@Test
public void whenGetPathWithSingleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/test")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("Path /t?st is accessed");
}
3.2. ‘ соответствует 0 или более символов в сегменте пути *
Если мы укажем шаблон пути как:“/example/*Id”,, он будет соответствовать шаблонам путиlike:”/example/Id”, “/example/tutorialId”, «/ example / articleId» и т. Д .:
private RouterFunction routingFunction() {
returnroute(
GET("/example/*Id"),
serverRequest -> ok().body(fromObject("/example/*Id path was accessed"))); }
@Test
public void whenGetMultipleCharWildcard_thenGotPathPattern()
throws Exception {
client.get()
.uri("/example/tutorialId")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/example/*Id path was accessed");
}
3.3. ‘ * 'Соответствует 0 или более сегментов пути до конца пути *
В этом случае сопоставление с образцом не ограничивается одним сегментом пути. Если мы укажем шаблон как“/resources/**”,, он сопоставит все пути с любым количеством сегментов пути после“/resources/”:
private RouterFunction routingFunction() {
return RouterFunctions.resources(
"/resources/**",
new ClassPathResource("resources/")));
}
@Test
public void whenAccess_thenGot() throws Exception {
client.get()
.uri("/resources/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("content of file test.txt");
}
3.4. ‘\{example:[a-z]+}' Regex в переменной пути
Мы также можем указать регулярное выражение для значения переменной пути. Итак, если наш шаблон похож на“/\{example:[a-z]+}”,, значением переменной пути“example” будет любой сегмент пути, который соответствует регулярному выражению give:
private RouterFunction routingFunction() {
return route(GET("/{example:[a-z]+}"),
serverRequest -> ok()
.body(fromObject("/{example:[a-z]+} was accessed and "
+ "example=" + serverRequest.pathVariable("example"))));
}
@Test
public void whenGetRegexInPathVarible_thenGotPathVariable()
throws Exception {
client.get()
.uri("/abcd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/{example:[a-z]+} was accessed and "
+ "example=abcd");
}
3.5. ‘/{var1} {var2} '_ Переменные с несколькими путями в одном сегменте пути
Spring 5 удостоверился, что несколько переменных пути будут разрешены в одном сегменте пути, только если они разделены разделителем. Только тогда Spring сможет различить две разные переменные пути:
private RouterFunction routingFunction() {
return route(
GET("/{var1}_{var2}"),
serverRequest -> ok()
.body(fromObject( serverRequest.pathVariable("var1") + " , "
+ serverRequest.pathVariable("var2"))));
}
@Test
public void whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables()
throws Exception {
client.get()
.uri("/example_tutorial")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("example , tutorial");
}
4. Заключение
В этой статье мы рассмотрели новые средства сопоставления URL-адресов в Spring 5, а также те, которые доступны в более старых версиях Spring.
Как всегда, реализацию всех рассмотренных нами примеров можно найти вover on GitHub.