diff --git a/spring-5-reactive/pom.xml b/spring-5-reactive/pom.xml
index 5d7cf0d7e5..e5b35de2f5 100644
--- a/spring-5-reactive/pom.xml
+++ b/spring-5-reactive/pom.xml
@@ -28,7 +28,7 @@
org.springframework.boot
- spring-boot-starter-web
+ spring-boot-starter-tomcat
org.springframework.boot
diff --git a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java
similarity index 93%
rename from spring-5/src/main/java/com/baeldung/web/PathPatternController.java
rename to spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java
index 6fd972f2a4..f5a5d9e769 100644
--- a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/PathPatternController.java
@@ -1,4 +1,4 @@
-package com.baeldung.web;
+package com.baeldung.reactive.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java
new file mode 100644
index 0000000000..ee06b94be7
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/Actor.java
@@ -0,0 +1,23 @@
+package com.baeldung.reactive.urlmatch;
+
+class Actor {
+ private String firstname;
+ private String lastname;
+
+ public Actor() {
+ }
+
+ public Actor(String firstname, String lastname) {
+ this.firstname = firstname;
+ this.lastname = lastname;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+}
diff --git a/spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java
similarity index 98%
rename from spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java
rename to spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java
index 2a6d04538c..78f40be57a 100644
--- a/spring-5/src/main/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctions.java
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctions.java
@@ -1,4 +1,4 @@
-package com.baeldung.functional;
+package com.baeldung.reactive.urlmatch;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java
new file mode 100644
index 0000000000..0781230379
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FormHandler.java
@@ -0,0 +1,41 @@
+package com.baeldung.reactive.urlmatch;
+
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers;
+import static org.springframework.web.reactive.function.BodyExtractors.toFormData;
+import static org.springframework.web.reactive.function.BodyInserters.fromObject;
+import static org.springframework.web.reactive.function.server.ServerResponse.ok;
+
+public class FormHandler {
+
+ Mono handleLogin(ServerRequest request) {
+ return request.body(toFormData())
+ .map(MultiValueMap::toSingleValueMap)
+ .filter(formData -> "baeldung".equals(formData.get("user")))
+ .filter(formData -> "you_know_what_to_do".equals(formData.get("token")))
+ .flatMap(formData -> ok().body(Mono.just("welcome back!"), String.class))
+ .switchIfEmpty(ServerResponse.badRequest()
+ .build());
+ }
+
+ Mono handleUpload(ServerRequest request) {
+ return request.body(toDataBuffers())
+ .collectList()
+ .flatMap(dataBuffers -> ok().body(fromObject(extractData(dataBuffers).toString())));
+ }
+
+ private AtomicLong extractData(List dataBuffers) {
+ AtomicLong atomicLong = new AtomicLong(0);
+ dataBuffers.forEach(d -> atomicLong.addAndGet(d.asByteBuffer()
+ .array().length));
+ return atomicLong;
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java
new file mode 100644
index 0000000000..2ea5420a2b
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/FunctionalWebApplication.java
@@ -0,0 +1,80 @@
+package com.baeldung.reactive.urlmatch;
+
+import static org.springframework.web.reactive.function.BodyInserters.fromObject;
+import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
+import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
+import static org.springframework.web.reactive.function.server.RequestPredicates.path;
+import static org.springframework.web.reactive.function.server.RouterFunctions.route;
+import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
+import static org.springframework.web.reactive.function.server.ServerResponse.ok;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
+import org.springframework.boot.web.server.WebServer;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.http.server.reactive.HttpHandler;
+import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.server.WebHandler;
+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
+
+import reactor.core.publisher.Flux;
+
+public class FunctionalWebApplication {
+
+ private static final Actor BRAD_PITT = new Actor("Brad", "Pitt");
+ private static final Actor TOM_HANKS = new Actor("Tom", "Hanks");
+ private static final List actors = new CopyOnWriteArrayList<>(Arrays.asList(BRAD_PITT, TOM_HANKS));
+
+ private RouterFunction routingFunction() {
+ FormHandler formHandler = new FormHandler();
+
+ RouterFunction restfulRouter = route(GET("/"), serverRequest -> ok().body(Flux.fromIterable(actors), Actor.class)).andRoute(POST("/"), serverRequest -> serverRequest.bodyToMono(Actor.class)
+ .doOnNext(actors::add)
+ .then(ok().build()));
+
+ return route(GET("/test"), serverRequest -> ok().body(fromObject("helloworld"))).andRoute(POST("/login"), formHandler::handleLogin)
+ .andRoute(POST("/upload"), formHandler::handleUpload)
+ .and(RouterFunctions.resources("/files/**", new ClassPathResource("files/")))
+ .andNest(path("/actor"), restfulRouter)
+ .filter((request, next) -> {
+ System.out.println("Before handler invocation: " + request.path());
+ return next.handle(request);
+ });
+ }
+
+ WebServer start() throws Exception {
+ WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
+ HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
+ .filter(new IndexRewriteFilter())
+ .build();
+
+ Tomcat tomcat = new Tomcat();
+ tomcat.setHostname("localhost");
+ tomcat.setPort(9090);
+ Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+ ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);
+ Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet);
+ rootContext.addServletMappingDecoded("/", "httpHandlerServlet");
+
+ TomcatWebServer server = new TomcatWebServer(tomcat);
+ server.start();
+ return server;
+
+ }
+
+ public static void main(String[] args) {
+ try {
+ new FunctionalWebApplication().start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java
new file mode 100644
index 0000000000..2eb252ed2b
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/urlmatch/IndexRewriteFilter.java
@@ -0,0 +1,27 @@
+package com.baeldung.reactive.urlmatch;
+
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+class IndexRewriteFilter implements WebFilter {
+
+ @Override
+ public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
+ ServerHttpRequest request = serverWebExchange.getRequest();
+ if (request.getURI()
+ .getPath()
+ .equals("/")) {
+ return webFilterChain.filter(serverWebExchange.mutate()
+ .request(builder -> builder.method(request.getMethod())
+ .contextPath(request.getPath()
+ .toString())
+ .path("/test"))
+ .build());
+ }
+ return webFilterChain.filter(serverWebExchange);
+ }
+
+}
diff --git a/spring-5-reactive/src/main/resources/files/hello.txt b/spring-5-reactive/src/main/resources/files/hello.txt
new file mode 100644
index 0000000000..b6fc4c620b
--- /dev/null
+++ b/spring-5-reactive/src/main/resources/files/hello.txt
@@ -0,0 +1 @@
+hello
\ No newline at end of file
diff --git a/spring-5-reactive/src/main/resources/files/test/test.txt b/spring-5-reactive/src/main/resources/files/test/test.txt
new file mode 100644
index 0000000000..30d74d2584
--- /dev/null
+++ b/spring-5-reactive/src/main/resources/files/test/test.txt
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java
similarity index 93%
rename from spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java
rename to spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java
index 7a38fa697f..21ba11616d 100644
--- a/spring-5/src/test/java/com/baeldung/functional/ExploreSpring5URLPatternUsingRouterFunctionsTest.java
+++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.functional;
+package com.baeldung.reactive.urlmatch;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -6,7 +6,9 @@ import org.junit.Test;
import org.springframework.boot.web.server.WebServer;
import org.springframework.test.web.reactive.server.WebTestClient;
-public class ExploreSpring5URLPatternUsingRouterFunctionsTest {
+import com.baeldung.reactive.urlmatch.ExploreSpring5URLPatternUsingRouterFunctions;
+
+public class ExploreSpring5URLPatternUsingRouterFunctionsIntegrationTest {
private static WebTestClient client;
private static WebServer server;
diff --git a/spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java
similarity index 92%
rename from spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java
rename to spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java
index c2ed8ff071..9f31608ff7 100644
--- a/spring-5/src/test/java/com/baeldung/web/PathPatternsUsingHandlerMethodIntegrationTest.java
+++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/urlmatch/PathPatternsUsingHandlerMethodIntegrationTest.java
@@ -1,6 +1,5 @@
-package com.baeldung.web;
+package com.baeldung.reactive.urlmatch;
-import com.baeldung.Spring5Application;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -8,8 +7,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
+import com.baeldung.reactive.Spring5ReactiveApplication;
+import com.baeldung.reactive.controller.PathPatternController;
+
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = Spring5Application.class)
+@SpringBootTest(classes = Spring5ReactiveApplication.class)
public class PathPatternsUsingHandlerMethodIntegrationTest {
private static WebTestClient client;