diff --git a/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java b/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java
index 9b7b838247b..ef949d2d65c 100644
--- a/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java
+++ b/spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java
@@ -16,9 +16,12 @@
package org.springframework.web.util;
import java.net.URI;
+import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
+import org.springframework.util.Assert;
+
/**
* Default implementation of {@link UriTemplateHandler} that relies on
* {@link UriComponentsBuilder} internally.
@@ -28,9 +31,42 @@ import java.util.Map;
*/
public class DefaultUriTemplateHandler implements UriTemplateHandler {
+ private String baseUrl;
+
private boolean parsePath;
+ /**
+ * Configure a base URL to prepend URI templates with. The base URL should
+ * have a scheme and host but may also contain a port and a partial path.
+ * Individual URI templates then may provide the remaining part of the URL
+ * including additional path, query and fragment.
+ *
+ *
Note: Individual URI templates are expanded and
+ * encoded before being appended to the base URL. Therefore the base URL is
+ * expected to be fully expanded and encoded, which can be done with the help
+ * of {@link UriComponentsBuilder}.
+ *
+ * @param baseUrl the base URL.
+ */
+ public void setBaseUrl(String baseUrl) {
+ if (baseUrl != null) {
+ UriComponents uriComponents = UriComponentsBuilder.fromUriString(baseUrl).build();
+ Assert.hasText(uriComponents.getScheme(), "'baseUrl' must have a scheme");
+ Assert.hasText(uriComponents.getHost(), "'baseUrl' must have a host");
+ Assert.isNull(uriComponents.getQuery(), "'baseUrl' cannot have a query");
+ Assert.isNull(uriComponents.getFragment(), "'baseUrl' cannot have a fragment");
+ }
+ this.baseUrl = baseUrl;
+ }
+
+ /**
+ * Return the configured base URL.
+ */
+ public String getBaseUrl() {
+ return this.baseUrl;
+ }
+
/**
* Whether to parse the path of a URI template string into path segments.
*
If set to {@code true} the path of parsed URI templates is decomposed
@@ -55,17 +91,19 @@ public class DefaultUriTemplateHandler implements UriTemplateHandler {
@Override
public URI expand(String uriTemplate, Map uriVariables) {
- UriComponentsBuilder builder = initBuilder(uriTemplate);
- return builder.build().expand(uriVariables).encode().toUri();
+ UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
+ UriComponents uriComponents = uriComponentsBuilder.build().expand(uriVariables).encode();
+ return insertBaseUrl(uriComponents);
}
@Override
public URI expand(String uriTemplate, Object... uriVariableValues) {
- UriComponentsBuilder builder = initBuilder(uriTemplate);
- return builder.build().expand(uriVariableValues).encode().toUri();
+ UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
+ UriComponents uriComponents = uriComponentsBuilder.build().expand(uriVariableValues).encode();
+ return insertBaseUrl(uriComponents);
}
- protected UriComponentsBuilder initBuilder(String uriTemplate) {
+ protected UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate);
if (shouldParsePath()) {
List pathSegments = builder.build().getPathSegments();
@@ -77,4 +115,17 @@ public class DefaultUriTemplateHandler implements UriTemplateHandler {
return builder;
}
+ protected URI insertBaseUrl(UriComponents uriComponents) {
+ if (getBaseUrl() == null || uriComponents.getHost() != null) {
+ return uriComponents.toUri();
+ }
+ String url = getBaseUrl() + uriComponents.toUriString();
+ try {
+ return new URI(url);
+ }
+ catch (URISyntaxException ex) {
+ throw new IllegalArgumentException("Invalid URL after inserting base URL: " + url, ex);
+ }
+ }
+
}
diff --git a/spring-web/src/test/java/org/springframework/web/util/DefaultUriTemplateHandlerTests.java b/spring-web/src/test/java/org/springframework/web/util/DefaultUriTemplateHandlerTests.java
index 18eae557fcb..1642351edc0 100644
--- a/spring-web/src/test/java/org/springframework/web/util/DefaultUriTemplateHandlerTests.java
+++ b/spring-web/src/test/java/org/springframework/web/util/DefaultUriTemplateHandlerTests.java
@@ -39,6 +39,24 @@ public class DefaultUriTemplateHandlerTests {
}
+ @Test
+ public void baseUrl() throws Exception {
+ this.handler.setBaseUrl("http://localhost:8080");
+ URI actual = this.handler.expand("/myapiresource");
+
+ URI expected = new URI("http://localhost:8080/myapiresource");
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void baseUrlWithPartialPath() throws Exception {
+ this.handler.setBaseUrl("http://localhost:8080/context");
+ URI actual = this.handler.expand("/myapiresource");
+
+ URI expected = new URI("http://localhost:8080/context/myapiresource");
+ assertEquals(expected, actual);
+ }
+
@Test
public void expandWithFullPath() throws Exception {
Map vars = new HashMap(2);
@@ -49,11 +67,11 @@ public class DefaultUriTemplateHandlerTests {
URI actual = this.handler.expand(template, vars);
URI expected = new URI("http://example.com/hotels/1/pic/pics/logo.png");
- assertEquals("Invalid expanded template", expected, actual);
+ assertEquals(expected, actual);
}
@Test
- public void expandWithFullPathParsedIntoPathSegments() throws Exception {
+ public void expandWithFullPathAndParsePathEnabled() throws Exception {
Map vars = new HashMap(2);
vars.put("hotel", "1");
vars.put("publicpath", "pics/logo.png");
@@ -64,7 +82,7 @@ public class DefaultUriTemplateHandlerTests {
URI actual = this.handler.expand(template, vars);
URI expected = new URI("http://example.com/hotels/1/pic/pics%2Flogo.png/size/150x150");
- assertEquals("Invalid expanded template", expected, actual);
+ assertEquals(expected, actual);
}
}