Skip to content

Commit 1ba0625

Browse files
committed
Add baseUrl to DefaultUriTemplateHandler
Issue: SPR-13035
1 parent 01d1e71 commit 1ba0625

File tree

2 files changed

+77
-8
lines changed

2 files changed

+77
-8
lines changed

spring-web/src/main/java/org/springframework/web/util/DefaultUriTemplateHandler.java

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
package org.springframework.web.util;
1717

1818
import java.net.URI;
19+
import java.net.URISyntaxException;
1920
import java.util.List;
2021
import java.util.Map;
2122

23+
import org.springframework.util.Assert;
24+
2225
/**
2326
* Default implementation of {@link UriTemplateHandler} that relies on
2427
* {@link UriComponentsBuilder} internally.
@@ -28,9 +31,42 @@
2831
*/
2932
public class DefaultUriTemplateHandler implements UriTemplateHandler {
3033

34+
private String baseUrl;
35+
3136
private boolean parsePath;
3237

3338

39+
/**
40+
* Configure a base URL to prepend URI templates with. The base URL should
41+
* have a scheme and host but may also contain a port and a partial path.
42+
* Individual URI templates then may provide the remaining part of the URL
43+
* including additional path, query and fragment.
44+
*
45+
* <p><strong>Note: </strong>Individual URI templates are expanded and
46+
* encoded before being appended to the base URL. Therefore the base URL is
47+
* expected to be fully expanded and encoded, which can be done with the help
48+
* of {@link UriComponentsBuilder}.
49+
*
50+
* @param baseUrl the base URL.
51+
*/
52+
public void setBaseUrl(String baseUrl) {
53+
if (baseUrl != null) {
54+
UriComponents uriComponents = UriComponentsBuilder.fromUriString(baseUrl).build();
55+
Assert.hasText(uriComponents.getScheme(), "'baseUrl' must have a scheme");
56+
Assert.hasText(uriComponents.getHost(), "'baseUrl' must have a host");
57+
Assert.isNull(uriComponents.getQuery(), "'baseUrl' cannot have a query");
58+
Assert.isNull(uriComponents.getFragment(), "'baseUrl' cannot have a fragment");
59+
}
60+
this.baseUrl = baseUrl;
61+
}
62+
63+
/**
64+
* Return the configured base URL.
65+
*/
66+
public String getBaseUrl() {
67+
return this.baseUrl;
68+
}
69+
3470
/**
3571
* Whether to parse the path of a URI template string into path segments.
3672
* <p>If set to {@code true} the path of parsed URI templates is decomposed
@@ -55,17 +91,19 @@ public boolean shouldParsePath() {
5591

5692
@Override
5793
public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
58-
UriComponentsBuilder builder = initBuilder(uriTemplate);
59-
return builder.build().expand(uriVariables).encode().toUri();
94+
UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
95+
UriComponents uriComponents = uriComponentsBuilder.build().expand(uriVariables).encode();
96+
return insertBaseUrl(uriComponents);
6097
}
6198

6299
@Override
63100
public URI expand(String uriTemplate, Object... uriVariableValues) {
64-
UriComponentsBuilder builder = initBuilder(uriTemplate);
65-
return builder.build().expand(uriVariableValues).encode().toUri();
101+
UriComponentsBuilder uriComponentsBuilder = initUriComponentsBuilder(uriTemplate);
102+
UriComponents uriComponents = uriComponentsBuilder.build().expand(uriVariableValues).encode();
103+
return insertBaseUrl(uriComponents);
66104
}
67105

68-
protected UriComponentsBuilder initBuilder(String uriTemplate) {
106+
protected UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
69107
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate);
70108
if (shouldParsePath()) {
71109
List<String> pathSegments = builder.build().getPathSegments();
@@ -77,4 +115,17 @@ protected UriComponentsBuilder initBuilder(String uriTemplate) {
77115
return builder;
78116
}
79117

118+
protected URI insertBaseUrl(UriComponents uriComponents) {
119+
if (getBaseUrl() == null || uriComponents.getHost() != null) {
120+
return uriComponents.toUri();
121+
}
122+
String url = getBaseUrl() + uriComponents.toUriString();
123+
try {
124+
return new URI(url);
125+
}
126+
catch (URISyntaxException ex) {
127+
throw new IllegalArgumentException("Invalid URL after inserting base URL: " + url, ex);
128+
}
129+
}
130+
80131
}

spring-web/src/test/java/org/springframework/web/util/DefaultUriTemplateHandlerTests.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ public void setUp() throws Exception {
3939
}
4040

4141

42+
@Test
43+
public void baseUrl() throws Exception {
44+
this.handler.setBaseUrl("http://localhost:8080");
45+
URI actual = this.handler.expand("/myapiresource");
46+
47+
URI expected = new URI("http://localhost:8080/myapiresource");
48+
assertEquals(expected, actual);
49+
}
50+
51+
@Test
52+
public void baseUrlWithPartialPath() throws Exception {
53+
this.handler.setBaseUrl("http://localhost:8080/context");
54+
URI actual = this.handler.expand("/myapiresource");
55+
56+
URI expected = new URI("http://localhost:8080/context/myapiresource");
57+
assertEquals(expected, actual);
58+
}
59+
4260
@Test
4361
public void expandWithFullPath() throws Exception {
4462
Map<String, String> vars = new HashMap<String, String>(2);
@@ -49,11 +67,11 @@ public void expandWithFullPath() throws Exception {
4967
URI actual = this.handler.expand(template, vars);
5068

5169
URI expected = new URI("http://example.com/hotels/1/pic/pics/logo.png");
52-
assertEquals("Invalid expanded template", expected, actual);
70+
assertEquals(expected, actual);
5371
}
5472

5573
@Test
56-
public void expandWithFullPathParsedIntoPathSegments() throws Exception {
74+
public void expandWithFullPathAndParsePathEnabled() throws Exception {
5775
Map<String, String> vars = new HashMap<String, String>(2);
5876
vars.put("hotel", "1");
5977
vars.put("publicpath", "pics/logo.png");
@@ -64,7 +82,7 @@ public void expandWithFullPathParsedIntoPathSegments() throws Exception {
6482
URI actual = this.handler.expand(template, vars);
6583

6684
URI expected = new URI("http://example.com/hotels/1/pic/pics%2Flogo.png/size/150x150");
67-
assertEquals("Invalid expanded template", expected, actual);
85+
assertEquals(expected, actual);
6886
}
6987

7088
}

0 commit comments

Comments
 (0)