1. Обзор
Весна 5 принесла новый Анализатор шаблонов путей для разбора шаблонов шаблонов URI . Это альтернатива ранее использованному AntPathMatcher .
AntPathMatcher был реализацией сопоставления шаблонов путей в стиле муравьев. Анализатор шаблонов путей разбивает путь на связанный список Элементов пути . Эта цепочка элементов Path берется классом Path Pattern для быстрого сопоставления шаблонов.
С помощью синтаксического анализатора Path Pattern также была введена поддержка нового синтаксиса переменной URI.
В этой статье мы рассмотрим новые/обновленные сопоставители шаблонов URL-адресов, представленные в Spring 5.0 WebFlux , а также те, которые были там с более старых версий Spring.
2. Новый шаблон URL-адреса соответствует весне 5.0
В выпуске Spring 5.0 добавлен очень простой в использовании синтаксис переменной URI: {*foo} для захвата любого количества сегментов пути в конце шаблона.
2.1. Синтаксис переменной URI {*foo} С использованием метода обработчика
Давайте рассмотрим пример шаблона переменной URI {*foo} другой пример с использованием @GetMapping и метода обработчика. Все, что мы дадим в пути после “/spring 5” , будет сохранено в переменной path “id”:
@GetMapping("/spring5/{*id}") public String URIVariableHandler(@PathVariable String id) { return id; }
@Test public void whenMultipleURIVariablePattern_thenGotPathVariable() { client.get() .uri("/spring5/baeldung/tutorial") .exchange() .expectStatus() .is2xxSuccessful() .expectBody() .equals("/baeldung/tutorial"); client.get() .uri("/spring5/baeldung") .exchange() .expectStatus() .is2xxSuccessful() .expectBody() .equals("/baeldung"); }
2.2. Синтаксис переменной URI {*foo} С использованием Функции Маршрутизатора
Давайте рассмотрим пример нового шаблона пути переменной URI с использованием функции Router :
private RouterFunctionroutingFunction() { return route(GET("/test/{*id}"), serverRequest -> ok().body(fromValue(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/{*пути к файлам}”. В этом случае, если путь /files/hello.txt, значение переменной path “пути к файлам” будет “/hello.txt”, в то время как, если путь /files/test/test.txt, значение “пути к файлам” .
Наша функция маршрутизации для доступа к файловым ресурсам в каталоге /files/ :
private RouterFunctionroutingFunction() { return RouterFunctions.resources( "/files/{*filepaths}", new ClassPathResource("files/"))); }
Предположим, что ваши текстовые файлы hello.txt и test.txt содержат “привет” и “тест” соответственно. Это можно продемонстрировать с помощью тестового случая 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. Все эти шаблоны работают как с функцией маршрутизатора , так и с методами обработчика с помощью @GetMapping .
3.1. “?” Соответствует Ровно Одному Символу
Если мы зададим шаблон пути как: “/t? st “, это будет соответствовать таким путям, как: “/тест” и “/вкус”, но не “/тест “ и “/тест”.
Пример кода, использующего функцию маршрутизатора и его тестовый случай JUnit:
private RouterFunctionroutingFunction() { return route(GET("/t?st"), serverRequest -> ok().body(fromValue("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 или более символам В сегменте Пути
Если мы зададим шаблон пути как: “/baeldung/*Id”, это будет соответствовать шаблонам пути как: “/baeldung/Id”, “/baeldung/tutorialId”, “/baeldung/articleId” и т. Д:
private RouterFunctionroutingFunction() { returnroute( GET("/baeldung/*Id"), serverRequest -> ok().body(fromValue("/baeldung/*Id path was accessed"))); } @Test public void whenGetMultipleCharWildcard_thenGotPathPattern() throws Exception { client.get() .uri("/baeldung/tutorialId") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo("/baeldung/*Id path was accessed"); }
3.3. ‘**’ Соответствует 0 или более Сегментам пути До конца Пути
В этом случае сопоставление шаблонов не ограничивается одним сегментом пути. Если мы зададим шаблон как “/ресурсы/**”, он будет соответствовать всем путям к любому количеству сегментов пути после “/ресурсы/”:
private RouterFunctionroutingFunction() { 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. Регулярное выражение ‘{baeldung:[a-z]+}’ в переменной Path
Мы также можем указать регулярное выражение для значения переменной path. Поэтому, если наш шаблон похож на “/{baeldung:[a-z]+}”, значением переменной path “baeldung” будет любой сегмент пути, соответствующий регулярному выражению gives:
private RouterFunctionroutingFunction() { return route(GET("/{baeldung:[a-z]+}"), serverRequest -> ok() .body(fromValue("/{baeldung:[a-z]+} was accessed and " + "baeldung=" + serverRequest.pathVariable("baeldung")))); } @Test public void whenGetRegexInPathVarible_thenGotPathVariable() throws Exception { client.get() .uri("/abcd") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo("/{baeldung:[a-z]+} was accessed and " + "baeldung=abcd"); }
3.5. ‘/{var1}_{var2}’ Несколько переменных пути в одном сегменте пути
Весна 5 убедилась, что несколько переменных пути будут разрешены в одном сегменте пути только при разделении разделителем. Только тогда Spring сможет различать две разные переменные пути:
private RouterFunctionroutingFunction() { return route( GET("/{var1}_{var2}"), serverRequest -> ok() .body(fromValue( serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2")))); } @Test public void whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables() throws Exception { client.get() .uri("/baeldung_tutorial") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo("baeldung , tutorial"); }
4. Заключение
В этой статье мы рассмотрели новые совпадения URL-адресов в Spring 5, а также те, которые доступны в более старых версиях Spring.
Как всегда, реализацию всех примеров, которые мы обсуждали, можно найти на GitHub .