private Mono<Resource> resolveVersionedResource(@Nullable ServerWebExchange exchange, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) { VersionStrategy versionStrategy = getStrategyForPath(requestPath); if (versionStrategy == null) { return Mono.empty(); } String candidate = versionStrategy.extractVersion(requestPath); if (StringUtils.isEmpty(candidate)) { return Mono.empty(); } String simplePath = versionStrategy.removeVersion(requestPath, candidate); return chain.resolveResource(exchange, simplePath, locations) .filterWhen(resource -> versionStrategy.getResourceVersion(resource) .map(actual -> { if (candidate.equals(actual)) { return true; } else { if (logger.isTraceEnabled()) { String logPrefix = exchange != null ? exchange.getLogPrefix() : ""; logger.trace(logPrefix + "Found resource for \"" + requestPath + "\", but version [" + candidate + "] does not match"); } return false; } })) .map(resource -> new FileNameVersionedResource(resource, candidate)); }
@Test public void resolveResourceExisting() { String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.just(expected)); this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); Resource actual = this.resolver .resolveResourceInternal(null, file, this.locations, this.chain) .block(Duration.ofMillis(5000)); assertEquals(expected, actual); verify(this.chain, times(1)).resolveResource(null, file, this.locations); verify(this.versionStrategy, never()).extractVersion(file); }
@Test public void resolveResourceNoVersionInPath() { String file = "bar.css"; given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty()); given(this.versionStrategy.extractVersion(file)).willReturn(""); this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); Resource actual = this.resolver .resolveResourceInternal(null, file, this.locations, this.chain) .block(Duration.ofMillis(5000)); assertNull(actual); verify(this.chain, times(1)).resolveResource(null, file, this.locations); verify(this.versionStrategy, times(1)).extractVersion(file); }
@Test public void resolveResourceVersionDoesNotMatch() { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); given(this.chain.resolveResource(null, versionFile, this.locations)).willReturn(Mono.empty()); given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.just(expected)); given(this.versionStrategy.extractVersion(versionFile)).willReturn(version); given(this.versionStrategy.removeVersion(versionFile, version)).willReturn(file); given(this.versionStrategy.getResourceVersion(expected)).willReturn(Mono.just("newer-version")); this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); Resource actual = this.resolver .resolveResourceInternal(null, versionFile, this.locations, this.chain) .block(Duration.ofMillis(5000)); assertNull(actual); verify(this.versionStrategy, times(1)).getResourceVersion(expected); }
@Test public void resolveResourceNoResourceAfterVersionRemoved() { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; given(this.chain.resolveResource(null, versionFile, this.locations)).willReturn(Mono.empty()); given(this.chain.resolveResource(null, file, this.locations)).willReturn(Mono.empty()); given(this.versionStrategy.extractVersion(versionFile)).willReturn(version); given(this.versionStrategy.removeVersion(versionFile, version)).willReturn(file); this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); Resource actual = this.resolver .resolveResourceInternal(null, versionFile, this.locations, this.chain) .block(Duration.ofMillis(5000)); assertNull(actual); verify(this.versionStrategy, times(1)).removeVersion(versionFile, version); }
@Test public void resolveResourceSuccess() { String versionFile = "bar-version.css"; String version = "version"; String file = "bar.css"; Resource expected = new ClassPathResource("test/" + file, getClass()); MockServerHttpRequest request = MockServerHttpRequest.get("/resources/bar-version.css").build(); ServerWebExchange exchange = MockServerWebExchange.from(request); given(this.chain.resolveResource(exchange, versionFile, this.locations)).willReturn(Mono.empty()); given(this.chain.resolveResource(exchange, file, this.locations)).willReturn(Mono.just(expected)); given(this.versionStrategy.extractVersion(versionFile)).willReturn(version); given(this.versionStrategy.removeVersion(versionFile, version)).willReturn(file); given(this.versionStrategy.getResourceVersion(expected)).willReturn(Mono.just(version)); this.resolver.setStrategyMap(Collections.singletonMap("/**", this.versionStrategy)); Resource actual = this.resolver .resolveResourceInternal(exchange, versionFile, this.locations, this.chain) .block(Duration.ofMillis(5000)); assertEquals(expected.getFilename(), actual.getFilename()); verify(this.versionStrategy, times(1)).getResourceVersion(expected); assertThat(actual, instanceOf(HttpResource.class)); assertEquals("\"" + version + "\"", ((HttpResource)actual).getResponseHeaders().getETag()); }
String candidateVersion = versionStrategy.extractVersion(requestPath); if (StringUtils.isEmpty(candidateVersion)) { if (logger.isTraceEnabled()) {