Understanding the Spring @RequestMapping Annotation

Understanding the Spring @RequestMapping Annotation

17 Comments

@RequestMapping is one of the most common annotation used in Spring Web applications. This annotation maps HTTP requests to handler methods of MVC and REST controllers.

In this post, you’ll see how versatile the @RequestMapping annotation is when used to map Spring MVC controller methods.

Request Mapping Basics

In Spring MVC applications, the RequestDispatcher (Front Controller Below) servlet is responsible for routing incoming HTTP requests to handler methods of controllers.

When configuring Spring MVC, you need to specify the mappings between the requests and handler methods.

Spring MVC Dispatcher Servlet and @RequestMappingTo configure the mapping of web requests, you use the @RequestMapping annotation.

The @RequestMapping annotation can be applied to class-level and/or method-level in a controller.

The class-level annotation maps a specific request path or pattern onto a controller. You can then apply additional method-level annotations to make mappings more specific to handler methods.

Here is an example of the @RequestMapping annotation applied to both class and methods.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping("/")
  String get(){
    //mapped to hostname:port/home/
    return "Hello from get";
  }
  @RequestMapping("/index")
  String index(){
    //mapped to hostname:port/home/index/
    return "Hello from index";
  }
}

With the preceding code, requests to /home will be handled by get() while request to /home/index will be handled by index().

@RequestMapping with Multiple URIs

You can have multiple request mappings for a method. For that add one @RequestMapping annotation with a list of values.

@RestController
@RequestMapping("/home")
public class IndexController {

@RequestMapping(value={"", "/page", "page*","view/*,**/msg"})
  String indexMultipleMapping(){
    return "Hello from index multiple mapping.";
  }
}

As you can see in this code, @RequestMapping supports wildcards and ant-style paths. For the preceding code, all these URLs will be handled by indexMultipleMapping().

  • localhost:8080/home
  • localhost:8080/home/
  • localhost:8080/home/page
  • localhost:8080/home/pageabc
  • localhost:8080/home/view/
  • localhost:8080/home/view/view

@RequestMapping with @RequestParam

The @RequestParam annotation is used with @RequestMapping to bind a web request parameter to the parameter of the handler method.

The @RequestParam annotation can be used with or without a value. The value specifies the request param that needs to be mapped to the handler method parameter, as shown in this code snippet.

@RestController	
@RequestMapping("/home")
public class IndexController {
  
  @RequestMapping(value = "/id")								
  String getIdByValue(@RequestParam("id") String personId){
    System.out.println("ID is "+personId);
    return "Get ID from query string of URL with value element";
  }
  @RequestMapping(value = "/personId")							
  String getId(@RequestParam String personId){
    System.out.println("ID is "+personId);	
    return "Get ID from query string of URL without value element";	
  }
}

In Line 6 of this code, the request param id will be mapped to the personId parameter personId of the getIdByValue() handler method.

An example URL is this:
localhost:8090/home/id?id=5

The value element of @RequestParam can be omitted if the request param and handler method parameter names are same, as shown in Line 11.

An example URL is this:
localhost:8090/home/personId?personId=5

The required element of @RequestParam defines whether the parameter value is required or not.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/name")
  String getName(@RequestParam(value = "person", required = false) String personName){
    return "Required element of request param";
  }
}

In this code snippet, as the required element is specified as false, the getName() handler method will be called for both of these URLs:

  • /home/name?person=xyz
  • /home/name

The default value of the @RequestParam is used to provide a default value when the request param is not provided or is empty.

@RestController	
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/name")
  String getName(@RequestParam(value = "person", defaultValue = "John") String personName ){
    return "Required element of request param";
  }
}

In this code, if the person request param is empty in a request, the getName() handler method will receive the default value John as its parameter.

Using @RequestMapping with HTTP Method

The Spring MVC @RequestMapping annotation is capable of handling HTTP request methods, such as GET, PUT, POST, DELETE, and PATCH.

By default all requests are assumed to be of HTTP GET type.

In order to define a request mapping with a specific HTTP method, you need to declare the HTTP method in @RequestMapping using the method element as follows.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(method = RequestMethod.GET)
  String get(){
    return "Hello from get";									
  }
  @RequestMapping(method = RequestMethod.DELETE)
  String delete(){
    return "Hello from delete";
  }
  @RequestMapping(method = RequestMethod.POST)
  String post(){
    return "Hello from post";
  }
  @RequestMapping(method = RequestMethod.PUT)
  String put(){
    return "Hello from put";
  }
  @RequestMapping(method = RequestMethod.PATCH)
  String patch(){
    return "Hello from patch";
  }
}

In the code snippet above, the method element of the @RequestMapping annotations indicates the HTTP method type of the HTTP request.

All the handler methods will handle requests coming to the same URL ( /home), but will depend on the HTTP method being used.

For example, a POST request to /home will be handled by the post() method. While a DELETE request to /home will be handled by the delete() method.

You can see how Spring MVC will map the other methods using this same logic.

Using @RequestMapping with Producible and Consumable

The request mapping types can be narrowed down using the produces and consumes elements of the @RequestMapping annotation.

In order to produce the object in the requested media type, you use the produces element of @RequestMapping in combination with the @ResponseBody annotation.

You can also consume the object with the requested media type using the consumes element of @RequestMapping in combination with the @RequestBody annotation.

The code to use producible and consumable with @RequestMapping is this.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/prod", produces = {"application/JSON"})
  @ResponseBody
  String getProduces(){
    return "Produces attribute";
  }

  @RequestMapping(value = "/cons", consumes = {"application/JSON", "application/XML"})
  String getConsumes(){
    return "Consumes attribute";
  }
}

In this code, the getProduces() handler method produces a JSON response. The getConsumes() handler method consumes JSON as well as XML present in requests.

@RequestMapping with Headers

The @RequestMapping annotation provides a header element to narrow down the request mapping based on headers present in the request.

You can specify the header element as myHeader = myValue.

@RestController	
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/head", headers = {"content-type=text/plain"})
  String post(){	
    return "Mapping applied along with headers";	
  }								
}

In the above code snippet, the headers attribute of the @RequestMapping annotation narrows down the mapping to the post() method. With this, the post() method will handle requests to /home/head whose content-type header specifies plain text as the value.

You can also indicate multiple header values like this:

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/head", headers = {"content-type=text/plain", "content-type=text/html"})		  String post(){
    return "Mapping applied along with headers";
  }								
}

Here it implies that both text/plain as well as text/html are accepted by the post() handler method.

@RequestMapping with Request Parameters

The params element of the @RequestMapping annotation further helps to narrow down request mapping. Using the params element, you can have multiple handler methods handling requests to the same URL, but with different parameters.

You can define params as myParams = myValue. You can also use the negation operator to specify that a particular parameter value is not supported in the request.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/fetch", params = {"personId=10"})
  String getParams(@RequestParam("personId") String id){
    return "Fetched parameter using params attribute = "+id;
  }
  @RequestMapping(value = "/fetch", params = {"personId=20"})
    String getParamsDifferent(@RequestParam("personId") String id){
    return "Fetched parameter using params attribute = "+id;
  }
}

In this code snippet, both the getParams() and getParamsDifferent() methods will handle requests coming to the same URL ( /home/fetch) but will execute depending on the params element.

For example, when the URL is /home/fetch?id=10 the getParams() handler method will be executed with the id value 10.. For the URL, localhost:8080/home/fetch?personId=20, the getParamsDifferent() handler method gets executed with the id value 20.

Using @RequestMapping with Dynamic URIs

The @RequestMapping annotation is used in combination with the @PathVaraible annotation to handle dynamic URIs. In this use case, the URI values can act as the parameter of the handler methods in the controller. You can also use regular expressions to only accept the dynamic URI values that match the regular expression.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping(value = "/fetch/{id}", method = RequestMethod.GET)
  String getDynamicUriValue(@PathVariable String id){
    System.out.println("ID is "+id);
    return "Dynamic URI parameter fetched";						
  } 
  @RequestMapping(value = "/fetch/{id:[a-z]+}/{name}", method = RequestMethod.GET)
    String getDynamicUriValueRegex(@PathVariable("name") String name){
    System.out.println("Name is "+name);
    return "Dynamic URI parameter fetched using regex";		
  } 
}

In this code, the method getDynamicUriValue() will execute for a request to localhost:8080/home/fetch/10. Also, the id parameter of the getDynamicUriValue() handler method will be populated with the value 10 dynamically.

The method getDynamicUriValueRegex() will execute for a request to localhost:8080/home/fetch/category/shirt. However, an exception will be thrown for a request to/home/fetch/10/shirt as it does not match the regular expression.

@PathVariable works differently from @RequestParam. You use @RequestParam to obtain the values of the query parameters from the URI. On the other hand, you use @PathVariable to obtain the parameter values from the URI template.

The @RequestMapping Default Handler Method

In the controller class you can have default handler method that gets executed when there is a request for a default URI.

Here is an example of a default handler method.

@RestController
@RequestMapping("/home")
public class IndexController {
  @RequestMapping()
  String default(){									
    return "This is a default method for the class";
  }
}

In this code, A request to /home will be handled by the default() method as the annotation does not specify any value.

@RequestMapping Shortcuts

Spring 4.3 introduced method-level variants, also known as composed annotations of @RequestMapping. The composed annotations better express the semantics of the annotated methods. They act as wrapper to @RequestMapping and have become the standard ways of defining the endpoints.

For example, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
The method level variants are:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

The following code shows using the composed annotations.

@RestController
@RequestMapping("/home")
public class IndexController {
  @GetMapping("/person")
  public @ResponseBody ResponseEntity<String> getPerson() {
    return new ResponseEntity<String>("Response from GET", HttpStatus.OK);
  }
  @GetMapping("/person/{id}")
  public @ResponseBody ResponseEntity<String> getPersonById(@PathVariable String id){
    return new ResponseEntity<String>("Response from GET with id " +id,HttpStatus.OK);				  }
  @PostMapping("/person")
  public @ResponseBody ResponseEntity<String> postPerson() {
    return new ResponseEntity<String>("Response from POST method", HttpStatus.OK);
  }
  @PutMapping("/person")
  public @ResponseBody ResponseEntity<String> putPerson() {
    return new ResponseEntity<String>("Response from PUT method", HttpStatus.OK);
  }
  @DeleteMapping("/person")
  public @ResponseBody ResponseEntity<String> deletePerson() {
    return new ResponseEntity<String>("Response from DELETE method", HttpStatus.OK); 
  }
  @PatchMapping("/person")
  public @ResponseBody ResponseEntity<String> patchPerson() {
    return new ResponseEntity<String>("Response from PATCH method", HttpStatus.OK);	
  }
}

In this code, each of the handler methods are annotated with the composed variants of @RequestMapping. Although, each variant can be interchangeably used with @RequestMapping with the method attribute, it’s considered a best practice to use the composed variant. Primarily because the composed annotations reduce the configuration metadata on the application side and the code is more readable.

@RequestMapping Conclusion

As you can see in this post, the @RequestMapping  annotation is very versatile. You can use this annotation to configure Spring MVC to handle a variety of use cases. It can be used to configure traditional web page requests, and well as RESTFul web services in Spring MVC.

About jt

    You May Also Like

    17 comments on “Understanding the Spring @RequestMapping Annotation

    1. September 13, 2017 at 2:25 pm

      is this correct? @PathVariable works differently from @RequestParam. You use @PathVariable to obtain the values of the query parameters from the URI. On the other hand, you use @RequestParam to obtain the parameter values from the URI template.

      Reply
      • September 13, 2017 at 2:34 pm

        Correct

        Reply
    2. September 22, 2017 at 5:06 pm

      I thought query parameters are those params after the ‘?’ in the URI, (?queryParam=value&queryParam2=value2). So you use @RequestParam. And the URI template is of the form /fetch/{id}, so you use @PathVariable to obtain the param values. Did I misunderstood the statement above?

      Reply
      • September 23, 2017 at 3:15 am

        That’s correct. @RequestParm is used for query parameters (that follows ‘?’) in URL, whereas @PathVariable for {placeholder} values that can keep dynamically changing in URL.

        Reply
    3. November 18, 2017 at 11:50 pm

      hi thanx for your share. But i have a quest.
      What about the “dispatcher-servlet.xml” and “web.xml”… can you show me your xml files.
      Thanx.

      Reply
      • November 20, 2017 at 10:15 am

        These are no longer required.

        Reply
    4. January 10, 2018 at 10:24 pm

      Hi, Thanks for the useful blog. I have a requirement to create multiple instance of RestController with different dao, service instance properties. I’m working on to convert Jersey rest code to spring boot rest. I have sample code of Jersey implementation in stackoverflow. Please let me know if you could comment on this.

      https://stackoverflow.com/questions/46876938/how-to-create-multiple-instances-of-restcontroller-in-spring-boot-application

      Thanks in advance.

      Reply
    5. May 8, 2018 at 2:06 am

      Nice summary. The only thing missing to make it a little better would be to show that handling of Objects both as input (in a POST for example) and as a response. Of course this would probably end up Jackson or some other OJM/OXM discussion.

      Reply
    6. July 12, 2018 at 4:37 am

      Why would one add @ResponseBody annotation in a class annotated with @RestController?
      @RestController itself contains @ResponseBody…

      Reply
    7. August 3, 2018 at 10:57 am

      Is it possible to specify a list of request parameters in a request mapping?

      I have the following mapping:
      @PostMapping(value = “/test/url”, params = { “id={10, 20}” })

      Yet when I submit the following request:
      http://localhost:8080/test/url?id=10&id=20

      I get the following error:
      ServletRequestParameterException: Parameter conditions “id={10, 20}” not met for actual request parameters: id={10, 20}

      Reply
    8. October 4, 2018 at 9:20 pm

      Correction: The “method” value of @RequestMapping defaults to an empty array — it does NOT default to the GET method. So, one should always be explicit, to avoid possibly nondeterministic behavior if multiple annotations can apply to the same request URL.

      See https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#method–

      Reply
    9. November 22, 2019 at 4:55 am

      Java is the brandd and most powerful programmic language ever. It’s features like cross platform supported is one of the most powerful fetures, AEM is also a java based technology, So have a look.
      aem architecture

      Reply
    10. June 16, 2020 at 2:54 pm

      You are using @Produces=”application/json” and returning a simple string. i just want to know how spring can process this without returning a json convertible object.

      Reply

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.