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();
// Результат "/hotel%20list/New%20York?q=foo%2Bbar"
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri()
// Результат "/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.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ