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.
To 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.
Cj
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.
jt
Correct
Cj
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?
Ximanta Sarma
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.
Yunus Emre Incu
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.
jt
These are no longer required.
Samy
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.
Richard B
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.
Simo
Why would one add @ResponseBody annotation in a class annotated with @RestController?
@RestController itself contains @ResponseBody…
DK
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}
Sam Y
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–
Lana Rohdes
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
Prabhat
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.