diff --git a/spring-mvc-simple-2/pom.xml b/spring-mvc-simple-2/pom.xml
index 74302cff78..ca911b2719 100644
--- a/spring-mvc-simple-2/pom.xml
+++ b/spring-mvc-simple-2/pom.xml
@@ -18,6 +18,11 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
diff --git a/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/Application.java b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/Application.java
new file mode 100644
index 0000000000..7db6ac3755
--- /dev/null
+++ b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/Application.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring.slash;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@SpringBootApplication
+public class Application implements WebMvcConfigurer {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/SlashParsingController.java b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/SlashParsingController.java
new file mode 100644
index 0000000000..635587ee5b
--- /dev/null
+++ b/spring-mvc-simple-2/src/main/java/com/baeldung/spring/slash/SlashParsingController.java
@@ -0,0 +1,31 @@
+package com.baeldung.spring.slash;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("slash")
+public class SlashParsingController {
+
+ @GetMapping("mypaths/{anything}")
+ public String pathVariable(@PathVariable("anything") String anything) {
+ return anything;
+ }
+
+ @GetMapping("all/**")
+ public String allDirectories(HttpServletRequest request) {
+ return request.getRequestURI()
+ .split(request.getContextPath() + "/all/")[1];
+ }
+
+ @GetMapping("all")
+ public String queryParameter(@RequestParam("param") String param) {
+ return param;
+ }
+
+}
diff --git a/spring-mvc-simple-2/src/test/java/com/baeldung/spring/slash/SlashParsingControllerIntTest.java b/spring-mvc-simple-2/src/test/java/com/baeldung/spring/slash/SlashParsingControllerIntTest.java
new file mode 100644
index 0000000000..d81b34f7bf
--- /dev/null
+++ b/spring-mvc-simple-2/src/test/java/com/baeldung/spring/slash/SlashParsingControllerIntTest.java
@@ -0,0 +1,87 @@
+package com.baeldung.spring.slash;
+
+import static org.junit.Assert.assertEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.net.URI;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+@AutoConfigureMockMvc
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class SlashParsingControllerIntTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ public void whenUsingPathVariablemWithoutSlashes_thenStatusOk() throws Exception {
+ final String stringWithoutSlashes = "noslash";
+
+ MvcResult mvcResult = mockMvc.perform(get("/slash/mypaths/" + stringWithoutSlashes))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ assertEquals(stringWithoutSlashes, mvcResult.getResponse()
+ .getContentAsString());
+ }
+
+ @Test
+ public void whenUsingPathVariableWithSlashes_thenStatusNotFound() throws Exception {
+ final String stringWithSlashes = "url/with/slashes";
+
+ mockMvc.perform(get("/slash/mypaths/" + stringWithSlashes))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void givenAllFallbackEndpoint_whenUsingPathWithSlashes_thenStatusOk() throws Exception {
+ final String stringWithSlashes = "url/for/testing/purposes";
+
+ MvcResult mvcResult = mockMvc.perform(get("/slash/all/" + stringWithSlashes))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ assertEquals(stringWithSlashes, mvcResult.getResponse()
+ .getContentAsString());
+ }
+
+ @Test
+ public void givenAllFallbackEndpoint_whenUsingConsecutiveSlashes_thenPathNormalized() throws Exception {
+ final String stringWithSlashes = "http://myurl.com";
+
+ MvcResult mvcResult = mockMvc.perform(get("/slash/all/" + stringWithSlashes))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String stringWithSlashesNormalized = URI.create("/slash/all/" + stringWithSlashes)
+ .normalize()
+ .toString()
+ .split("/slash/all/")[1];
+
+ assertEquals(stringWithSlashesNormalized, mvcResult.getResponse()
+ .getContentAsString());
+ }
+
+ @Test
+ public void whenUsingSlashesInQueryParam_thenParameterAccepted() throws Exception {
+ final String stringWithSlashes = "url/for////testing/purposes";
+
+ MvcResult mvcResult = mockMvc.perform(get("/slash/all").param("param", stringWithSlashes))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ assertEquals(stringWithSlashes, mvcResult.getResponse()
+ .getContentAsString());
+ }
+
+}