UriComponentsBuilder
helps to build URI’s from URI templates with variables:
UriComponents uriComponents = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}") // (1)
.queryParam("q", "{q}") // (2)
.encode() // (3)
.build(); // (4)
URI uri = uriComponents.expand("Westin", "123").toUri(); // (5)
-
Static factory method with a URI template.
-
Add and/or replace URI components.
-
Request to have the URI template and URI variables encoded.
-
Build a
UriComponents
. -
Expand variables, and obtain the
URI
.
The above can be consolidated into one chain and shortened with buildAndExpand
:
URI uri = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("Westin", "123")
.toUri();
It can be shortened further by going directly to URI (which implies encoding):
URI uri = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Or shorter further yet, with a full URI template:
URI uri = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
Spring MVC and Spring WebFlux
UriComponentsBuilder implements UriBuilder
. A UriBuilder
in turn
can be created with a UriBuilderFactory
. Together UriBuilderFactory
and UriBuilder
provide a pluggable mechanism to build URIs from URI templates, based on shared
configuration such as a base url, encoding preferences, and others.
The RestTemplate
and the WebClient
can be configured with a UriBuilderFactory
to customize the preparation of URIs. DefaultUriBuilderFactory
is a default
implementation of UriBuilderFactory
that uses UriComponentsBuilder
internally and
exposes shared configuration options.
RestTemplate
example:
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "http://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VARIABLES);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
WebClient
example:
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
String baseUrl = "http://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VARIABLES);
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
In addition DefaultUriBuilderFactory
can also be used directly. It is similar to using
UriComponentsBuilder
but instead of static factory methods, it is an actual instance
that holds configuration and preferences:
String baseUrl = "http://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
Spring MVC and Spring WebFlux
UriComponentsBuilder
exposes encoding options at 2 levels:
-
{api-spring-framework}/web/util/UriComponentsBuilder.html#encode--[UriComponentsBuilder#encode()] - pre-encodes the URI template first, then strictly encodes URI variables when expanded.
-
{api-spring-framework}/web/util/UriComponents.html#encode--[UriComponents#encode()] - encodes URI components after URI variables are expanded.
Both options replace non-ASCII and illegal characters with escaped octets, however option 1 also replaces characters with reserved meaning that appear in URI variables.
Tip
|
Consider ";" which is legal in a path but has reserved meaning. Option 1 replaces ";" with "%3B" in URI variables but not in the URI template. By contrast, option 2 never replaces ";" since it is a legal character in a path. |
For most cases option 1 is likely to give the expected result because it treats URI variables as opaque data to be fully encoded, while option 2 is useful only if URI variables intentionally contain reserved characters.
Example usage using option 1:
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri();
// Result is "/hotel%20list/New%20York?foo%2Bbar"
The above can be shortened by going directly to URI (which implies encoding):
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
Or shorter further yet, with a full URI template:
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
The WebClient
and the RestTemplate
expand and encode URI templates internally through
the UriBuilderFactory
strategy. Both can be configured with a custom strategy:
String baseUrl = "http://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// Customize the RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
The DefaultUriBuilderFactory
implementation uses UriComponentsBuilder
internally to
expand and encode URI templates. As a factory it provides a single place to configure
the approach to encoding based on one of the below encoding modes:
-
TEMPLATE_AND_VALUES
— usesUriComponentsBuilder#encode()
, corresponding to option 1 above, to pre-encode the URI template and strictly encode URI variables when expanded. -
VALUES_ONLY
— does not encode the URI template and instead applies strict encoding to URI variables viaUriUtils#encodeUriUriVariables
prior to expanding them into the template. -
URI_COMPONENTS
— usesUriComponents#encode()
, corresponding to option 2 above, to encode URI component value after URI variables are expanded. -
NONE
— no encoding is applied.
Out of the box the RestTemplate
is set to EncodingMode.URI_COMPONENTS
for historic
reasons and for backwards compatibility. The WebClient
relies on the default value
in DefaultUriBuilderFactory
which was changed from EncodingMode.URI_COMPONENTS
in
5.0.x to EncodingMode.TEMPLATE_AND_VALUES
in 5.1.