Skip to content

Commit 57e0c78

Browse files
committed
Polish
Issue: SPR-12323
1 parent c5d6cc4 commit 57e0c78

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/resource/WebJarsResourceResolver.java

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@
2929
* A {@code ResourceResolver} that delegates to the chain to locate a resource
3030
* and then attempts to find a matching versioned resource contained in a WebJar JAR file.
3131
*
32-
* <p>This allows WabJar users to use version-less paths in their templates, like {@code "/jquery/jquery.min.js"}
33-
* while this path is resolved to the unique version {@code "/jquery/1.2.0/jquery.min.js"}, which is a better fit
34-
* for HTTP caching and version management in applications.
32+
* <p>This allows WebJars.org users to write version agnostic paths in their templates,
33+
* like {@code <script src="/jquery/jquery.min.js"/>}.
34+
* This path will be resolved to the unique version {@code <script src="/jquery/1.2.0/jquery.min.js"/>},
35+
* which is a better fit for HTTP caching and version management in applications.
36+
*
37+
* <p>This also resolves Resources for version agnostic HTTP requests {@code "GET /jquery/jquery.min.js"}.
3538
*
3639
* <p>This resolver requires the "org.webjars:webjars-locator" library on classpath, and is automatically
3740
* registered if that library is present.
3841
*
3942
* @author Brian Clozel
4043
* @since 4.2
44+
* @see org.springframework.web.servlet.config.annotation.ResourceChainRegistration
4145
* @see <a href="http://www.webjars.org">webjars.org</a>
4246
*/
4347
public class WebJarsResourceResolver extends AbstractResourceResolver {
@@ -56,7 +60,12 @@ public WebJarsResourceResolver() {
5660
protected Resource resolveResourceInternal(HttpServletRequest request, String requestPath,
5761
List<? extends Resource> locations, ResourceResolverChain chain) {
5862

59-
return chain.resolveResource(request, requestPath, locations);
63+
Resource resolved = chain.resolveResource(request, requestPath, locations);
64+
if (resolved == null) {
65+
String webJarResourcePath = findWebJarResourcePath(requestPath);
66+
return chain.resolveResource(request, webJarResourcePath, locations);
67+
}
68+
return resolved;
6069
}
6170

6271
@Override
@@ -65,26 +74,31 @@ protected String resolveUrlPathInternal(String resourceUrlPath,
6574

6675
String path = chain.resolveUrlPath(resourceUrlPath, locations);
6776
if (path == null) {
68-
try {
69-
int startOffset = resourceUrlPath.startsWith("/") ? 1 : 0;
70-
int endOffset = resourceUrlPath.indexOf("/", 1);
71-
if (endOffset != -1) {
72-
String webjar = resourceUrlPath.substring(startOffset, endOffset);
73-
String partialPath = resourceUrlPath.substring(endOffset);
74-
String webJarPath = webJarAssetLocator.getFullPath(webjar, partialPath);
75-
return chain.resolveUrlPath(webJarPath.substring(WEBJARS_LOCATION_LENGTH), locations);
76-
}
77-
}
78-
catch (MultipleMatchesException ex) {
79-
logger.warn("WebJar version conflict for \"" + resourceUrlPath + "\"", ex);
77+
String webJarResourcePath = findWebJarResourcePath(resourceUrlPath);
78+
return chain.resolveUrlPath(webJarResourcePath, locations);
79+
}
80+
return path;
81+
}
82+
83+
protected String findWebJarResourcePath(String path) {
84+
try {
85+
int startOffset = path.startsWith("/") ? 1 : 0;
86+
int endOffset = path.indexOf("/", 1);
87+
if (endOffset != -1) {
88+
String webjar = path.substring(startOffset, endOffset);
89+
String partialPath = path.substring(endOffset);
90+
String webJarPath = webJarAssetLocator.getFullPath(webjar, partialPath);
91+
return webJarPath.substring(WEBJARS_LOCATION_LENGTH);
8092
}
81-
catch (IllegalArgumentException ex) {
82-
if (logger.isTraceEnabled()) {
83-
logger.trace("No WebJar resource found for \"" + resourceUrlPath + "\"");
84-
}
93+
} catch (MultipleMatchesException ex) {
94+
logger.warn("WebJar version conflict for \"" + path + "\"", ex);
95+
}
96+
catch (IllegalArgumentException ex) {
97+
if (logger.isTraceEnabled()) {
98+
logger.trace("No WebJar resource found for \"" + path + "\"");
8599
}
86100
}
87-
return path;
101+
return null;
88102
}
89103

90104
}

spring-webmvc/src/test/java/org/springframework/web/servlet/resource/WebJarsResourceResolverTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626
import java.util.Collections;
2727
import java.util.List;
2828

29+
import javax.servlet.http.HttpServletRequest;
30+
2931
import org.junit.Before;
3032
import org.junit.Test;
3133

3234
import org.springframework.core.io.ClassPathResource;
3335
import org.springframework.core.io.Resource;
36+
import org.springframework.mock.web.test.MockHttpServletRequest;
3437

3538
/**
3639
* Unit tests for
@@ -46,6 +49,8 @@ public class WebJarsResourceResolverTests {
4649

4750
private ResourceResolverChain chain;
4851

52+
private HttpServletRequest request = new MockHttpServletRequest();
53+
4954
@Before
5055
public void setup() {
5156
// for this to work, an actual WebJar must be on the test classpath
@@ -104,4 +109,31 @@ public void resolverUrlWebJarResourceNotFound() {
104109
verify(this.chain, times(1)).resolveUrlPath(file, this.locations);
105110
}
106111

112+
@Test
113+
public void resolveResourceExisting() {
114+
Resource expected = mock(Resource.class);
115+
this.locations = Collections.singletonList(new ClassPathResource("/META-INF/resources/webjars/", getClass()));
116+
String file = "/foo/2.3/foo.txt";
117+
given(this.chain.resolveResource(this.request, file, this.locations)).willReturn(expected);
118+
119+
Resource actual = this.resolver.resolveResource(this.request, file, this.locations, this.chain);
120+
121+
assertEquals(expected, actual);
122+
verify(this.chain, times(1)).resolveResource(this.request, file, this.locations);
123+
}
124+
125+
@Test
126+
public void resolveResourceWebJar() {
127+
Resource expected = mock(Resource.class);
128+
String file = "/underscorejs/underscore.js";
129+
String expectedPath = "/underscorejs/1.8.2/underscore.js";
130+
this.locations = Collections.singletonList(new ClassPathResource("/META-INF/resources/webjars/", getClass()));
131+
given(this.chain.resolveResource(this.request, expectedPath, this.locations)).willReturn(expected);
132+
133+
Resource actual = this.resolver.resolveResource(this.request, file, this.locations, this.chain);
134+
135+
assertEquals(expected, actual);
136+
verify(this.chain, times(1)).resolveResource(this.request, file, this.locations);
137+
}
138+
107139
}

0 commit comments

Comments
 (0)