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#encodeUriVariablesbefore 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.NONENo 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