diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java
index 049d03ce27..27302055a9 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java
@@ -123,14 +123,35 @@ public abstract class RouterFunctions {
* For instance
*
* Resource location = new FileSystemResource("public-resources/");
- * RoutingFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
+ * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
*
* @param pattern the pattern to match
* @param location the location directory relative to which resources should be resolved
* @return a router function that routes to resources
+ * @see #resourceLookupFunction(String, Resource)
*/
public static RouterFunction resources(String pattern, Resource location) {
- return resources(new PathResourceLookupFunction(pattern, location));
+ return resources(resourceLookupFunction(pattern, location));
+ }
+
+ /**
+ * Returns the resource lookup function used by {@link #resources(String, Resource)}.
+ * The returned function can be {@linkplain Function#andThen(Function) composed} on, for
+ * instance to return a default resource when the lookup function does not match:
+ *
+ * Mono<Resource> defaultResource = Mono.just(new ClassPathResource("index.html"));
+ * Function<ServerRequest, Mono<Resource>> lookupFunction =
+ * RouterFunctions.resourceLookupFunction("/resources/**", new FileSystemResource("public-resources/"))
+ * .andThen(resourceMono -> resourceMono.switchIfEmpty(defaultResource));
+ *
+ * RouterFunction<ServerResponse> resources = RouterFunctions.resources(lookupFunction);
+ *
+ * @param pattern the pattern to match
+ * @param location the location directory relative to which resources should be resolved
+ * @return the default resource lookup function for the given parameters.
+ */
+ public static Function> resourceLookupFunction(String pattern, Resource location) {
+ return new PathResourceLookupFunction(pattern, location);
}
/**
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java
index b734ffaa37..ee5342bcc2 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/PathResourceLookupFunctionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.web.reactive.function.server;
import java.io.File;
import java.io.IOException;
import java.net.URI;
+import java.util.function.Function;
import org.junit.Test;
import reactor.core.publisher.Mono;
@@ -95,4 +96,37 @@ public class PathResourceLookupFunctionTests {
.verify();
}
+ @Test
+ public void composeResourceLookupFunction() throws Exception {
+
+ Function> lookupFunction =
+ new PathResourceLookupFunction("/resources/**",
+ new ClassPathResource("org/springframework/web/reactive/function/server/"));
+
+ ClassPathResource defaultResource = new ClassPathResource("response.txt", getClass());
+
+ Function> customLookupFunction =
+ lookupFunction.andThen(resourceMono -> resourceMono
+ .switchIfEmpty(Mono.just(defaultResource)));
+
+ MockServerRequest request = MockServerRequest.builder()
+ .uri(new URI("http://localhost/resources/foo"))
+ .build();
+
+ Mono result = customLookupFunction.apply(request);
+ StepVerifier.create(result)
+ .expectNextMatches(resource -> {
+ try {
+ return defaultResource.getFile().equals(resource.getFile());
+ }
+ catch (IOException ex) {
+ return false;
+ }
+ })
+ .expectComplete()
+ .verify();
+
+ }
+
+
}
\ No newline at end of file