UriComponents
UriComponentsBuilder
helps you create URIs from URI templates with variables, as shown in the following example:
UriComponents uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.build();
URI uri = uriComponents.expand("Westin", "123").toUri();
- Static factory method with URI template.
- Add or replace URI components.
- Request to encode a URI template and URI variables.
- Collect
UriComponents
. - Expand the variables and get
URI
.
val uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.build()
val uri = uriComponents.expand("Westin", "123").toUri()
- Static factory method with URI template.
- Add or replace URI components.
- Request to encode a URI template and URI variables.
- Collect
UriComponents
. - We expand the variables and get
URI
.
The code from the previous example can be combined into one chain and shortened using buildAndExpand
, as shown in the following example:
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()
You can shorten it even further by going directly to the URI (which implies an encoding), as shown in the following example:
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");
You can shorten it even further using the full Template URI, as shown in the following example:
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
implements UriBuilder
. In turn, you can create a UriBuilder
using UriBuilderFactory
. Together, UriBuilderFactory
and UriBuilder
provide a plug-in mechanism for generating URIs from URI templates based on common configuration, such as the base URL, encoding options, and other details.
You can configure RestTemplate
and WebClient
using UriBuilderFactory
to configure URI preparation. DefaultUriBuilderFactory
is a default implementation of UriBuilderFactory
that uses UriComponentsBuilder
internally and exposes general configuration options.
In the following The example shows how to configure such a bean:
// 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
The following example configures a 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()
Also, you can use DefaultUriBuilderFactory
directly. This is similar to using UriComponentsBuilder
, but instead of static factory methods, it is an actual instance that stores configuration and parameters, as shown in the following example:
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 encoding
UriComponentsBuilder
opens encoding options at two levels:
UriComponentsBuilder#encode(): Pre-encodes the URI pattern first , and then strictly encodes the URI variables when expanding.
UriComponents#encode(): Encodes URI components after the URI extension -variables.
Both options replace non-ASCII and invalid characters with escaped octets. However, the first option also replaces characters with a reserved meaning that appear in variables.
In most cases, the first option will most likely produce the expected result because it treats URI variables as opaque data that must be fully encoded, while the second option is useful if URI variables intentionally contain reserved characters. The second option also works if you don't expand URI variables at all, because then anything that happens to look like a URI variable is encoded.
The following example uses the first option:
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"
You can shorten the code in the previous example by going directly to the URI (which implies an encoding), as shown in the following example:
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")
You can shorten it even further using the full URI template, as shown in the following example:
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
and RestTemplate
extend and encode URI templates internally using the UriBuilderFactory
strategy. Both options can be configured using a custom strategy, as shown in the following example:
String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// Configuring RestTemplate...
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// Configuring WebClient...
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}
Set up RestTemplate...
val restTemplate = RestTemplate().apply {
uriTemplateHandler = factory
}
// Setting up WebClient...
val client = WebClient.builder().uriBuilderFactory(factory).build()
The DefaultUriBuilderFactory
implementation uses UriComponentsBuilder
internally to extend and encode URI patterns. As a factory, it provides a single place to configure the encoding approach , based on one of the following encoding modes:
TEMPLATE_AND_VALUES
: Uses UriComponentsBuilder#encode()
corresponding to the first option in previous list, to pre-encode the URI pattern and strictly encode variables when expanding.VALUES_ONLY
: Does not encode the URI pattern and instead applies strictly encode URIs to variables viaUriUtils#encodeUriVariables
before expanding them into a template.URI_COMPONENT
: UsesUriComponents#encode()
, corresponding to the second option in the previous list, to encode the value of a URI component after expanding URI variables.NONE
No encoding is applied.
RestTemplate
is set to EncodingMode.URI_COMPONENT
for historical reasons and for backward compatibility. WebClient
accesses the default value in DefaultUriBuilderFactory
, which was changed from EncodingMode.URI_COMPONENT
in 5.0.x to EncodingMode.TEMPLATE_AND_VALUES
in 5.1.
GO TO FULL VERSION