Close

Spring MVC - URI matching, using setUseTrailingSlashMatch() method of RequestMappingHandlerMapping (legacy)

[Last Updated: Sep 26, 2026]

In this example, we will look at the outcome of using the setUseTrailingSlashMatch() method of RequestMappingHandlerMapping. This setting specifies whether to match URLs irrespective of the presence of a trailing slash. When enabled, a handler method mapped to "/users" also matches the URI "/users/" (but not "/user"). In the Spring MVC versions used in this example, the default value is true.


Deprecation setUseTrailingSlashMatch() was deprecated in Spring Framework 6.0, where its default also changed from true to false. As of Spring Framework 7.0, the method has been removed entirely, along with the equivalent PathPatternParser.setMatchOptionalTrailingSeparator() option — there is no direct configuration replacement. Applications that still need "/users" and "/users/" to resolve to the same handler should instead register a servlet UrlHandlerFilter (via UrlHandlerFilter.trailingSlashHandler("/**")) ahead of the dispatcher, or declare both paths explicitly on the handler method, e.g. @GetMapping({"/users", "/users/"}). The example below reflects the classic (now removed) API and is kept for historical/version-history reference.

Example

A controller

package com.logicbig.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;

@Controller
public class MyController {

    @ResponseBody
    @RequestMapping("/employee")
    public String employeeHandler() {
        return "response from employeeHandler()";
    }
}

Java Config:

First, we'll see the default behavior when setUseTrailingSlashMatch is left unconfigured (true by default, in the per Spring MVC 6 versions).

@Configuration
 @ComponentScan
 @EnableWebMvc
 public class AppConfig implements WebMvcConfigurer {
 }

To try examples, run embedded Jetty (configured in pom.xml of example project below):

mvn jetty:run

Output

As seen in the outputs above, both paths are mapped to our single handler method, employeeHandler().

Now let's set setUseTrailingSlashMatch to false.

Setting setUseTrailingSlashMatch=false

Let's configure RequestMappingHandlerMapping with the desired setting:

package com.logicbig.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;

@Configuration
@ComponentScan
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseTrailingSlashMatch(false);
    }
}

With the setting disabled, "/employee/" no longer matches and results in a 404, as seen above.

Tests

Test on default behavior (pre Spring 6).

package com.logicbig.example;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration(classes = TrailingSlashTrueTest.LocalConfig.class)
public class TrailingSlashTrueTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                                 .build();
    }

    @Test
    public void employeeMatchesWithoutTrailingSlash() throws Exception {
        mockMvc.perform(get("/employee"))
               .andExpect(status().isOk())
               .andExpect(content().string(
                       "response from employeeHandler()"));
    }

    @Test
    public void employeeMatchesWithTrailingSlash() throws Exception {
        mockMvc.perform(get("/employee/"))
               .andExpect(status().isOk())
               .andExpect(content().string(
                       "response from employeeHandler()"));
    }

    @Configuration
    @EnableWebMvc
    static class LocalConfig implements WebMvcConfigurer {
        @Bean
        public MyController myController(){
             return new MyController();
         }
    }
}
mvn clean test -Dtest="TrailingSlashTrueTest"

Output

$ mvn clean test -Dtest="TrailingSlashTrueTest"
[INFO] Scanning for projects...
[INFO]
[INFO] ------< com.logicbig.example:spring-set-use-trailing-slash-match >------
[INFO] Building spring-set-use-trailing-slash-match 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ spring-set-use-trailing-slash-match ---
[INFO] Deleting D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ spring-set-use-trailing-slash-match ---
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\src\main\resources
[INFO]
[INFO] --- compiler:3.3:compile (default-compile) @ spring-set-use-trailing-slash-match ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target\classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ spring-set-use-trailing-slash-match ---
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\src\test\resources
[INFO]
[INFO] --- compiler:3.3:testCompile (default-testCompile) @ spring-set-use-trailing-slash-match ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target\test-classes
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ spring-set-use-trailing-slash-match ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.TrailingSlashTrueTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.548 s -- in com.logicbig.example.TrailingSlashTrueTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.655 s
[INFO] Finished at: 2026-09-25T04:58:14-05:00
[INFO] ------------------------------------------------------------------------

Setting useTrailingSlashMatch = false

package com.logicbig.example;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@ContextConfiguration(classes = AppConfig.class)
public class TrailingSlashFalseTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void employeeMatchesWithoutTrailingSlash() throws Exception {
        mockMvc.perform(get("/employee"))
               .andExpect(status().isOk())
               .andExpect(content().string(
                       "response from employeeHandler()"));
    }

    @Test
    public void employeeWithTrailingSlashReturnsNotFound() throws Exception {
        mockMvc.perform(get("/employee/"))
               .andExpect(status().isNotFound());
    }
}
mvn clean test -Dtest="TrailingSlashFalseTest"

Output

$ mvn clean test -Dtest="TrailingSlashFalseTest"
[INFO] Scanning for projects...
[INFO]
[INFO] ------< com.logicbig.example:spring-set-use-trailing-slash-match >------
[INFO] Building spring-set-use-trailing-slash-match 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ spring-set-use-trailing-slash-match ---
[INFO] Deleting D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ spring-set-use-trailing-slash-match ---
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\src\main\resources
[INFO]
[INFO] --- compiler:3.3:compile (default-compile) @ spring-set-use-trailing-slash-match ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target\classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ spring-set-use-trailing-slash-match ---
[INFO] skip non existing resourceDirectory D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\src\test\resources
[INFO]
[INFO] --- compiler:3.3:testCompile (default-testCompile) @ spring-set-use-trailing-slash-match ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\example-projects\spring-mvc\handler-mapping\spring-set-use-trailing-slash-match\target\test-classes
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ spring-set-use-trailing-slash-match ---
[INFO] Using auto detected provider org.apache.maven.surefire.junit4.JUnit4Provider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.TrailingSlashFalseTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.560 s -- in com.logicbig.example.TrailingSlashFalseTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.628 s
[INFO] Finished at: 2026-09-25T04:59:04-05:00
[INFO] ------------------------------------------------------------------------
INFO: Skipping bean definition for [BeanMethod:name=myController,declaringClass=com.logicbig.example.TrailingSlashTrueTest$LocalConfig]: a definition for bean 'myController' already exists. This top-level bean definition is considered as an override.
WARNING: No mapping found for HTTP request with URI [/employee/] in DispatcherServlet with name ''

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 5.0.0.RELEASE (Spring Web MVC)
     Version Compatibility: 4.0.3.RELEASE - 5.3.39Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 4.0.3.RELEASE
    • 4.0.4.RELEASE
    • 4.0.5.RELEASE
    • 4.0.6.RELEASE
    • 4.0.7.RELEASE
    • 4.0.8.RELEASE
    • 4.0.9.RELEASE
    • 4.1.0.RELEASE
    • 4.1.1.RELEASE
    • 4.1.2.RELEASE
    • 4.1.3.RELEASE
    • 4.1.4.RELEASE
    • 4.1.5.RELEASE
    • 4.1.6.RELEASE
    • 4.1.7.RELEASE
    • 4.1.8.RELEASE
    • 4.1.9.RELEASE
    • 4.2.0.RELEASE
    • 4.2.1.RELEASE
    • 4.2.2.RELEASE
    • 4.2.3.RELEASE
    • 4.2.4.RELEASE
    • 4.2.5.RELEASE
    • 4.2.6.RELEASE
    • 4.2.7.RELEASE
    • 4.2.8.RELEASE
    • 4.2.9.RELEASE
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • 4.3.2.RELEASE
    • 4.3.3.RELEASE
    • 4.3.4.RELEASE
    • 4.3.5.RELEASE
    • 4.3.6.RELEASE
    • 4.3.7.RELEASE
    • 4.3.8.RELEASE
    • 4.3.9.RELEASE
    • 4.3.10.RELEASE
    • 4.3.11.RELEASE
    • 4.3.12.RELEASE
    • 4.3.13.RELEASE
    • 4.3.14.RELEASE
    • 4.3.15.RELEASE
    • 4.3.16.RELEASE
    • 4.3.17.RELEASE
    • 4.3.18.RELEASE
    • 4.3.19.RELEASE
    • 4.3.20.RELEASE
    • 4.3.21.RELEASE
    • 4.3.22.RELEASE
    • 4.3.23.RELEASE
    • 4.3.24.RELEASE
    • 4.3.25.RELEASE
    • 4.3.26.RELEASE
    • 4.3.27.RELEASE
    • 4.3.28.RELEASE
    • 4.3.29.RELEASE
    • 4.3.30.RELEASE
    • 5.0.0.RELEASE
    • 5.0.1.RELEASE
    • 5.0.2.RELEASE
    • 5.0.3.RELEASE
    • 5.0.4.RELEASE
    • 5.0.5.RELEASE
    • 5.0.6.RELEASE
    • 5.0.7.RELEASE
    • 5.0.8.RELEASE
    • 5.0.9.RELEASE
    • 5.0.10.RELEASE
    • 5.0.11.RELEASE
    • 5.0.12.RELEASE
    • 5.0.13.RELEASE
    • 5.0.14.RELEASE
    • 5.0.15.RELEASE
    • 5.0.16.RELEASE
    • 5.0.17.RELEASE
    • 5.0.18.RELEASE
    • 5.0.19.RELEASE
    • 5.0.20.RELEASE
    • 5.1.0.RELEASE
    • 5.1.1.RELEASE
    • 5.1.2.RELEASE
    • 5.1.3.RELEASE
    • 5.1.4.RELEASE
    • 5.1.5.RELEASE
    • 5.1.6.RELEASE
    • 5.1.7.RELEASE
    • 5.1.8.RELEASE
    • 5.1.9.RELEASE
    • 5.1.10.RELEASE
    • 5.1.11.RELEASE
    • 5.1.12.RELEASE
    • 5.1.13.RELEASE
    • 5.1.14.RELEASE
    • 5.1.15.RELEASE
    • 5.1.16.RELEASE
    • 5.1.17.RELEASE
    • 5.1.18.RELEASE
    • 5.1.19.RELEASE
    • 5.1.20.RELEASE
    • 5.2.0.RELEASE
    • 5.2.1.RELEASE
    • 5.2.2.RELEASE
    • 5.2.3.RELEASE
    • 5.2.4.RELEASE
    • 5.2.5.RELEASE
    • 5.2.6.RELEASE
    • 5.2.7.RELEASE
    • 5.2.8.RELEASE
    • 5.2.9.RELEASE
    • 5.2.10.RELEASE
    • 5.2.11.RELEASE
    • 5.2.12.RELEASE
    • 5.2.13.RELEASE
    • 5.2.14.RELEASE
    • 5.2.15.RELEASE
    • 5.2.16.RELEASE
    • 5.2.17.RELEASE
    • 5.2.18.RELEASE
    • 5.2.19.RELEASE
    • 5.2.20.RELEASE
    • 5.2.21.RELEASE
    • 5.2.22.RELEASE
    • 5.2.23.RELEASE
    • 5.2.24.RELEASE
    • 5.2.25.RELEASE
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.3.3
    • 5.3.4
    • javax.servlet-api:4.x
    • 5.3.5
    • 5.3.6
    • 5.3.7
    • 5.3.8
    • 5.3.9
    • 5.3.10
    • 5.3.11
    • 5.3.12
    • 5.3.13
    • 5.3.14
    • 5.3.15
    • 5.3.16
    • 5.3.17
    • 5.3.18
    • 5.3.19
    • 5.3.20
    • 5.3.21
    • 5.3.22
    • 5.3.23
    • 5.3.24
    • 5.3.25
    • 5.3.26
    • 5.3.27
    • 5.3.28
    • 5.3.29
    • 5.3.30
    • 5.3.31
    • 5.3.32
    • 5.3.33
    • 5.3.34
    • 5.3.35
    • 5.3.36
    • 5.3.37
    • 5.3.38
    • 5.3.39

    Versions in green have been tested.

  • spring-test 5.0.0.RELEASE (Spring TestContext Framework)
  • junit-jupiter-engine 5.0.0 (Module "junit-jupiter-engine" of JUnit 5)
  • javax.servlet-api 3.0.1 (Java Servlet API)
  • hamcrest 3.0 (Core API and libraries of hamcrest matcher framework)
  • JDK 1.8
  • Maven 3.9.11

Spring MVC - setUseTrailingSlashMatch() Example Select All Download
  • spring-set-use-trailing-slash-match
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • AppConfig.java
        • test
          • java
            • com
              • logicbig
                • example

    See Also

    Join