Close

Spring MVC - Mapping Requests with @RequestMapping

[Last Updated: Mar 4, 2026]

The annotation @RequestMapping

@RequestMapping is used to map request URLs to specific controllers.

Definition of RequestMapping

Version: 7.0.5
 package org.springframework.web.bind.annotation;
 @Target({ ElementType.TYPE, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Mapping
 @Reflective(ControllerMappingReflectiveProcessor.class)
 public @interface RequestMapping {
     String name() default ""; 1
     @AliasFor("path")
     String[] value() default {}; 2
     @AliasFor("value")
     String[] path() default {}; 3
     RequestMethod[] method() default {}; 4
     String[] params() default {}; 5
     String[] headers() default {}; 6
     String[] consumes() default {}; 7
     String[] produces() default {}; 8
     String version() default ""; 9
 }
1Assign a name to this mapping.
2The path mapping URIs — for example, "/profile".
3The path mapping URIs — for example, "/profile". (Since 4.2)
4The HTTP request methods to map to, narrowing the primary mapping: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
5The parameters of the mapped request, narrowing the primary mapping.
6The headers of the mapped request, narrowing the primary mapping.
7Narrows the primary mapping by media types that can be consumed by the mapped handler.
8Narrows the primary mapping by media types that can be produced by the mapped handler.
9Narrows the primary mapping by an API version. (Since 7.0)

All elements of @RequestMapping annotation are optional.

It's annotated with @Target(value={METHOD,TYPE}), so it can be used on class level or method level.

If @RequestMapping specifies a path on class level then all paths in the methods are relative.

@RequestMapping on the class level is not required. Without it, all paths are simply absolute, and not relative

The handler methods without @RequestMapping won't be mapped, even their enclosing class has @Controller and a valid @RequestMapping annotations.


Elements of @RequestMapping

String[] value

It's the URL mapping expression:

@RequestMapping("/users")
 @Controller
 public class UserController{
    ...
 }


Multiple URLs can be specified:

@RequestMapping({"/users", "/clients"})
 @Controller
 public class UserController{
    ...
 }

It may contain URI templates:

@RequestMapping("/users")
 @Controller
 public class UserController{
   @RequestMapping("/{userId}")
    public String handle(....){
     ....
    }
 }

The method handle() will map to /users/{userId}



URI Template Patterns may contain regex:

@RequestMapping("/{userId:[0-9]+}")


URI templates can be captured by handler's method parameter annotated with @PathVariable:

@RequestMapping("/{userId}")
    public void handle(@PathVariable("userId") String userId) {
            // ...
    }


A method without @RequestMapping won't be mapped, even though enclosing class annotations are valid. For example the following code will not map the method handleAllUsersRequest() and will return 404 error for the request /users:

@Controller
 @RequestMapping("/users")
 public class UserController {

  public String handleAllUsersRequest(){
        .....
  }
 }

To fix above mapping (for the request /users):

@Controller
 @RequestMapping("/users")
 public class UserController {

  @RequestMapping
  public String handleAllUsersRequest(){
        .....
  }
 }


On class level @RequestMapping("") or just @RequestMapping will map to root url "/" (example here).

If on class level no @RequestMapping annotation is used then on method level @RequestMapping("") will map to the root url ("/"), whereas, empty @RequestMapping (without path) will act as a fall back and will map to all URLs for which specific matches are not available (example here).



RequestMethod[] method

The HTTP request methods, this handler can support:

@Controller
@RequestMapping("/users")
public class UserController {

   @RequestMapping(value= "{id}", method = {RequestMethod.GET, RequestMethod.DELETE})
   public String handle(......){
     //..
   }
}


Per good design principles, it's better to define separate handler methods based on HTTP methods.

Different handler methods can uniquely be defined based on different HTTP methods (no ambiguity), even if they have same request URL path:

@Controller
@RequestMapping("/users")
public class UserController {

   @RequestMapping(value= "{id}", method = {RequestMethod.GET})
   public String handleGet(.....){
     //..
   }

   @RequestMapping(value= "{id}", method = {RequestMethod.DELETE})
   public String handleDelete(.....){
     //..
   }


}



String[] params

The query string parameters. The annotated method will only be mapped if the query string matches.

This is another level for defining handler methods uniquely (no ambiguity) or in other words to narrow down the primary mapping. In the following example the request /users?id=4 will be mapped to method handleUserId4 and the request /user?id=10 will be mapped to method handleUserId10:

@Controller
@RequestMapping("/users")
public class UserControllerParams {

    @RequestMapping(params = "id=4")
    public String handleUserId4(.....) {
        System.out.println("got param id = 4");
        return "view-name";
    }

    @RequestMapping(params = "id=10")
    public String handleUserId10(....) {
        System.out.println("got param id = 10");
        return "view-name";
    }
}

We don't have to necessarily capture the query param using @RequestParam as each method will only be called when params matches, that means we can safely use hardcoded param values inside the handler method.

Defining multiple query params:

@Controller
@RequestMapping("/users")
public class UserControllerParams {

    @RequestMapping(params = {"state=TX", "dept=IT"})
    public String handleRequest(.....) {
         ....
        return "view-name";
    }
}

We can skip the query param value part. In that case all request having the specified param name will be mapped regardless of their values:

@Controller
@RequestMapping("/users")
public class UserControllerParams {

    @RequestMapping(params = "dept")
    public String handleRequest(.....) {
         ....
        return "view-name";
    }
}


String[] headers

It's just like params element but instead of query params, it is used to specify HTTP headers key-value pair. That uniquely defines handlers (narrowing the primary mapping):

@Controller
@RequestMapping("/users")
public class UserControllerHeader {

    @RequestMapping(headers = "id=4")
    public String handleAllUsersRequest() {
        System.out.println("got header id = 4");
        return "view-name";
    }

    @RequestMapping(headers = "id=10")
    public String handleAllUsersRequest2() {
        System.out.println("got header id = 10");
        return "view-name";
    }

}



String[] consumes

It defines the consumable media types of the mapped request, narrowing the primary mapping.

It's based on Content Negotiation specifications.

@Controller
@RequestMapping("/users")
public class UserControllerConsume {

    @RequestMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
    public String handleJson(@RequestBody String s) {
        System.out.println("json body : " + s);
        return "view-name";
    }

    @RequestMapping(consumes = MediaType.APPLICATION_XML_VALUE)
    public String handleXML(@RequestBody String s) {
        System.out.println("xml body " + s);
        return "view-name";
    }
}

Expressions can be negated by using the "!" operator, as in "!text/plain", which matches all requests with a Content-Type other than "text/plain".

Mapping Requests with @RequestMapping

What is @RequestBody?

Annotation indicating a method parameter should be bound to the body of the web request. The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request.




String[] produces

The producible media types of the mapped request, narrowing the primary mapping.

@Controller
@RequestMapping("/users")
public class UserControllerProduce {

    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
     public  @ResponseBody String handleJson() {
        System.out.println("Got json request");
        return "{ \"userName\": \"Joe\"}";
    }

    @RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
    public @ResponseBody  String handleXML() {
        System.out.println("Got xml request");
        return "<userName>Joe</userName>";
    }
}

Expressions can be negated by using the "!" operator, as in "!text/plain", which matches all requests with a Accept other than "text/plain".




String[] path

Alias for 'value'

Ant-style path patterns are also supported (e.g. /**/users).

This example will match any URL ending with users e.g. /dept1/dept2/dept3/dept4/dept5/users

@Controller
@RequestMapping("/**/users")
public class UserControllerPath {

    @RequestMapping
    public void handleAllUsersRequest(HttpServletRequest request){
        System.out.println(request.getRequestURL());
    }
}

Also check out this to understand URI pattern matching in details.




String name

Assign a name to this mapping.



Placeholders in path pattern

@RequestMapping's value element can also have a placeholder ${...} pattern against a property source. Check out an example here.



String version (Spring 7+ new @RequestMapping element)

Spring Framework 7 introduces native, declarative API versioning support.

Versioning is implemented via a version attribute in @RequestMapping and related annotations (@GetMapping, @PostMapping, etc.).

Spring 7 introduces a declarative API versioning model that replaces manual path or header handling. By using the version attribute within @RequestMapping, developers can natively manage multiple API iterations.

  • Flexible Resolution: Versions can be automatically extracted from URL paths, Request Headers, query params or Media Types.
  • Global Configuration: The ApiVersionConfigurer allows for setting default versions and handling Deprecation or Sunset headers. query param.
  • Tooling Integration: Improved support for Spring Doc and OpenAPI to automatically generate version-specific documentation.
@EnableWebMvc
@Configuration
public class WebConfigApiVersioning implements WebMvcConfigurer {
    
    .....
 
    @Override
    public void configureApiVersioning(ApiVersionConfigurer configurer) {
        configurer.useQueryParam("v")
                  .addSupportedVersions("2.0", "3.0", "3.1");
    }
}
    @RequestMapping(version = "2")
    public String handleAllUsersRequest(){
       .....
    }

    @RequestMapping(version = "3+")
    public String handleAllUsersRequest3(){
       ..
    }

Example Project

Dependencies and Technologies Used:

  • spring-webmvc 7.0.5 (Spring Web MVC)
     Version Compatibility: 3.2.9.RELEASE - 7.0.5Version List
    ×

    Version compatibilities of spring-webmvc with this example:

      javax.servlet-api:3.x
    • 3.2.9.RELEASE
    • 3.2.10.RELEASE
    • 3.2.11.RELEASE
    • 3.2.12.RELEASE
    • 3.2.13.RELEASE
    • 3.2.14.RELEASE
    • 3.2.15.RELEASE
    • 3.2.16.RELEASE
    • 3.2.17.RELEASE
    • 3.2.18.RELEASE
    • 4.0.0.RELEASE
    • 4.0.1.RELEASE
    • 4.0.2.RELEASE
    • 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
    • javax.* -> jakarta.*
      jakarta.servlet-api:6.x
      Java 17 min
    • 6.0.0
    • 6.0.1
    • 6.0.2
    • 6.0.3
    • 6.0.4
    • 6.0.5
    • 6.0.6
    • 6.0.7
    • 6.0.8
    • 6.0.9
    • 6.0.10
    • 6.0.11
    • 6.0.12
    • 6.0.13
    • 6.0.14
    • 6.0.15
    • 6.0.16
    • 6.0.17
    • 6.0.18
    • 6.0.19
    • 6.0.20
    • 6.0.21
    • 6.0.22
    • 6.0.23
    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 6.2.16
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3
    • 7.0.4
    • 7.0.5

    Versions in green have been tested.

  • spring-test 7.0.5 (Spring TestContext Framework)
  • json-path 2.10.0 (A library to query and verify JSON)
  • jakarta.servlet-api 6.1.0 (Jakarta Servlet API documentation)
  • junit-jupiter-engine 6.0.2 (Module "junit-jupiter-engine" of JUnit)
  • hamcrest 3.0 (Core API and libraries of hamcrest matcher framework)
  • JDK 25
  • Maven 3.9.11

Spring MVC - @RequestMapping Examples Select All Download
  • spring-mvc-request-mapping
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • UserControllerConsume.java
        • test
          • java
            • com
              • logicbig
                • example

    See Also

    Join