UriComponents

UriComponentsBuilder допомагає створювати URI-ідентифікатори з URI-шаблонів зі змінними, як показано в наступному прикладі:

Java
UriComponents uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}") 
.queryParam("q", "{q}") 
.encode() 
.build(); 
URI uri = uriComponents.expand("Westin", "123").toUri();
  1. Статичний фабричний метод з URI-шаблоном.
  2. Додаємо або замінюємо URI-компоненти.
  3. Запит на кодування URI-шаблону та URI-змінних.
  4. Збираємо UriComponents.
  5. Розширюємо змінні та отримуємо URI.
Kotlin
val uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}") 
.queryParam("q", "{q}") 
.encode() 
.build() 
val uri = uriComponents.expand("Westin", "123").toUri()
  1. Статичний фабричний метод з URI-шаблоном.
  2. Додаємо або замінюємо URI-компоненти.
  3. Запит на кодування URI-шаблону та URI-змінних.
  4. Збираємо UriComponents.
  5. Розширюємо змінні та отримуємо URI.

Код із попереднього прикладу можна об'єднати в один ланцюжок і скоротити за допомогою buildAndExpand, як показано в наступному прикладі:

Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri();
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri()

Можна скоротити його ще більше шляхом безпосереднього переходу до URI-ідентифікатора (що передбачає кодування), як показано в наступному прикладі:

Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");

Можна скоротити його навіть ще більше за допомогою повного URI-шаблону, як показано в наступному прикладі:

Java
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
Kotlin
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123")

UriBuilder

UriComponentsBuilder реалізує UriBuilder. Можна створити UriBuilder за допомогою UriBuilderFactory. Водночас UriBuilderFactory та UriBuilder надають механізм, що підключається, для створення URI-ідентифікаторів з URI-шаблонів на основі загальної конфігурації, такої як базова URL-адреса, параметри кодування та інші деталі.

Можна конфігурувати RestTemplate та WebClient за допомогою UriBuilderFactory, щоб налаштувати підготовку URI-ідентифікаторів. DefaultUriBuilderFactory — це реалізація UriBuilderFactory за замовчуванням, яка використовує UriComponentsBuilder на внутрішньому рівні та відкриває загальні параметри конфігурації.

У наступному прикладі показано, як налаштувати такий бін:

Java
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
Kotlin
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val restTemplate = RestTemplate()
restTemplate.uriTemplateHandler = factory

У наступному прикладі конфігурується WebClient:

Java
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
Kotlin
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode
val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES
val client = WebClient.builder().uriBuilderFactory(factory).build()

До того ж, можна використовувати DefaultUriBuilderFactory безпосередньо. Це схоже на використання UriComponentsBuilder, але замість статичних фабричних методів це реальний екземпляр, який зберігає конфігурацію та параметри, як показано в наступному прикладі:

Java
String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Kotlin
val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)
val uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123")

Кодування URI

UriComponentsBuilder відкриває опції кодування на двох рівнях:

  • UriComponentsBuilder#encode(): Спочатку заздалегідь кодує URI-шаблон, а потім суворо кодує URI-змінні під час розширення.

  • UriComponents#encode(): Кодує URI-компоненти після розширення URI-змінних.

Обидві опції замінюють символи, що не належать до стандарту ASCII, і неприпустимі символи на екрановані октети. Однак перший варіант також замінює символи із зарезервованим значенням, які з'являються в змінних.

Розглянемо ";" перший варіант замінює ";" на "%3B" у змінних, але не в URI-шаблоні. На відміну від цього, другий варіант ніколи не замінює ";", оскільки він є допустимим символом у дорозі.

У більшості випадків перший варіант, швидше за все, дасть очікуваний результат, оскільки він враховує URI-змінні як непрозорі. дані, які мають бути повністю закодовані, в той час як другий варіант корисний, якщо URI-змінні свідомо містять зарезервовані символи. Другий варіант також працює, якщо не розширювати URI-змінні взагалі, оскільки в цьому випадку кодується все, що випадково буде схоже на URI-змінну.

У наступному прикладі використовується перший варіант:

Java
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri();
// Result "/hotel%20list/New%20York?q=foo%2Bbar"
Kotlin
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri()
// Result "/hotel%20list/New%20York?q=foo%2Bbar"

Можна скоротити код у попередньому прикладі шляхом безпосереднього переходу до URI-ідентифікатора (що має на увазі кодування), як показано в наступному прикладі:

Java
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar");
Kotlin
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")

Можна скоротити його навіть ще більше за допомогою повного URI- шаблону, як показано в наступному прикладі:

Java
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar");
Kotlin
val uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")

WebClient та RestTemplate розширюють та кодують URI-шаблони на внутрішньому рівні за допомогою стратегії UriBuilderFactory. Обидва варіанти можна конфігурувати за допомогою кастомної стратегії, як показано в наступному прикладі:

Java

String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// Налаштовуємо RestTemplate...
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// Налаштовуємо WebClient...
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
Kotlin

val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}
// Налаштовуємо RestTemplate...
val restTemplate = RestTemplate().apply {
uriTemplateHandler = factory
}
// Налаштовуємо WebClient...
val client = WebClient.builder().uriBuilderFactory(factory).build()

Реалізація DefaultUriBuilderFactory використовує UriComponentsBuilder на внутрішньому рівні для розширення та кодування URI-шаблонів. Як фабрика, вона надає єдине місце для конфігурування підходу до кодування, заснованого на одному з наведених нижче режимів кодування:

  • TEMPLATE_AND_VALUES: Використовує UriComponentsBuilder#encode (), що відповідає першій опції в попередньому списку, для попереднього кодування URI-шаблону та строгого кодування змінних при розширенні.

  • VALUES_ONLY: Не кодує URI-шаблон і замість цього застосовує суворе кодування до змінних URI-ідентифікаторів через UriUtils#encodeUriVariables перед тим, як розширити їх у шаблон.

  • URI_COMPONENT: Використовує UriComponents#encode(), що відповідає другому варіанту в попередньому списку, для кодування значення компонента URI-ідентифікатора після розширення URI-змінних.

  • NONE Кодування не застосовується.

RestTemplate встановлений у EncodingMode.URI_COMPONENT з історичних причин та для зворотної сумісності. WebClient звертається до значення за замовчуванням у DefaultUriBuilderFactory, яке було змінено з EncodingMode.URI_COMPONENT в 5.0.x на EncodingMode.TEMPLATE_AND_VALUES у 5.1.