UriComponents
UriComponentsBuilder
допомагає створювати URI-ідентифікатори з URI-шаблонів зі
змінними, як показано в наступному прикладі:
UriComponents uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.build();
URI uri = uriComponents.expand("Westin", "123").toUri();
- Статичний фабричний метод з URI-шаблоном.
- Додаємо або замінюємо URI-компоненти.
- Запит на кодування URI-шаблону та URI-змінних.
- Збираємо
UriComponents
. - Розширюємо змінні та отримуємо
URI
.
val uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.build()
val uri = uriComponents.expand("Westin", "123").toUri()
- Статичний фабричний метод з URI-шаблоном.
- Додаємо або замінюємо URI-компоненти.
- Запит на кодування URI-шаблону та URI-змінних.
- Збираємо
UriComponents
. - Розширюємо змінні та отримуємо
URI
.
Код із попереднього прикладу можна об'єднати в один ланцюжок і скоротити за допомогою
buildAndExpand
, як показано в наступному прикладі:
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri();
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri()
Можна скоротити його ще більше шляхом безпосереднього переходу до URI-ідентифікатора (що передбачає кодування), як показано в наступному прикладі:
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
val uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Можна скоротити його навіть ще більше за допомогою повного URI-шаблону, як показано в наступному прикладі:
URI uri = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
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
на внутрішньому рівні та відкриває загальні
параметри
конфігурації.
У наступному прикладі показано, як налаштувати такий бін:
// 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);
// 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
:
// 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();
// 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
, але замість статичних фабричних методів це реальний екземпляр, який зберігає
конфігурацію та параметри, як показано в наступному прикладі:
String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
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, і неприпустимі символи на екрановані октети. Однак перший варіант також замінює символи із зарезервованим значенням, які з'являються в змінних.
У більшості випадків перший варіант, швидше за все, дасть очікуваний результат, оскільки він враховує URI-змінні як непрозорі. дані, які мають бути повністю закодовані, в той час як другий варіант корисний, якщо URI-змінні свідомо містять зарезервовані символи. Другий варіант також працює, якщо не розширювати URI-змінні взагалі, оскільки в цьому випадку кодується все, що випадково буде схоже на URI-змінну.
У наступному прикладі використовується перший варіант:
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"
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-ідентифікатора (що має на увазі кодування), як показано в наступному прикладі:
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar");
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
Можна скоротити його навіть ще більше за допомогою повного URI- шаблону, як показано в наступному прикладі:
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar");
val uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
WebClient
та RestTemplate
розширюють та кодують URI-шаблони на внутрішньому рівні за
допомогою стратегії UriBuilderFactory
. Обидва варіанти можна конфігурувати за допомогою кастомної
стратегії, як показано в наступному прикладі:
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();
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.