Spring @RequestMapping annotation, part of Spring MVC module, is used for mapping HTTP requests to handler methods in the @Controller classes. This annotation allows sufficient flexibility to define custom URL patterns, HTTP methods, request parameters, headers, and more.
Let us understand how to use this annotation effectively in a Spring MVC application.
1. Using @RequestMapping Annotation
We can define the @RequestMapping annotation in two places:
- Class Level
- Method level
When applied at the class level, it applies to all handler methods as well. For example, look at the followng EmployeeController code having basic CRUD operations.
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/api/employees/*")
public class EmployeeController {
@RequestMapping
public String getModuleInfo(Model model) {
// return module info
return "employeesManagementInfo.xsd";
}
// Add a new employee
@RequestMapping(value = "/add", method = RequestMethod.POST)
public ResponseEntity<Employee> addEmployee(@RequestBody Employee employee) {
// Save in database
return new ResponseEntity<>(employee, HttpStatus.CREATED);
}
// Get an employee by ID
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public ResponseEntity<Employee> getEmployee(@PathVariable Long id) {
// Get from database
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
// Get all employees
@RequestMapping(value = "/all", method = RequestMethod.GET)
public ResponseEntity<List<Employee>> getAllEmployees() {
// Get from database
return new ResponseEntity<>(employeeList, HttpStatus.OK);
}
@RequestMapping(value={"/remove", "/delete"})
public ResponseEntity removeEmployee(@RequestParam("id") String id) {
//handle
}
}
If there are multiple URLs which can be mapped to single method then you can pass an array of string parameters having all different URLs to value attribute e.g. we did this for remove() method in above example. This method will be called if you call URL ‘/remove‘ or ‘/delete‘.
Another thing to note is that first method getModuleInfo() lacks a URL value. Since the class level uses the ‘/api/employees/*’ URL wildcard so this handler method is executed as a catch block if no other matched for any request. So any URL request (e.g., ‘/api/employees/data‘ triggers this method.
2. Stereotype Annotations
Since Spring 4.3, we have use 5 new specialized annotations in place of @RequestMapping annotation. These new annotations are merely composed annotations for clean and easy-to-understand code practices. They do not offer any functionality or performance improvement over @RequestMapping.
Annotation | Shorthand for |
---|---|
@GetMapping | @RequestMapping(method = RequestMethod.GET) |
@PostMapping | @RequestMapping(method = RequestMethod.POST) |
@PutMapping | @RequestMapping(method = RequestMethod.PUT) |
@DeleteMapping | @RequestMapping(method = RequestMethod.DELETE) |
@PatchMapping | @RequestMapping(method = RequestMethod.PATCH) |
Using these annotations, we can rewrite the EmployeeController APIs as follows:
@RestController
@RequestMapping("/api/employees/*")
public class EmployeeController {
@GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(@PathVariable Long id) {
// Method implementation
}
@PostMapping("/add")
public ResponseEntity<Employee> addEmployee(@RequestBody Employee employee) {
// Method implementation
}
}
3. Mapping URLs
The @RequestMapping annotation allows passing dynamic values in the path (called path parameters) and we can extract them using the @PathVariable annotation.
In the following example, we can pass different values for ‘userId‘ and ‘orderId‘ and they all map to the same handler method. Spring framework extracts both values from the URL and maps them to the respective parameters in the ‘getUserOrder()‘ method.
@Controller
@RequestMapping("/api/users")
public class UserController {
@RequestMapping("/{userId}/orders/{orderId}")
public String getUserOrder(@PathVariable("userId") Long userId,
@PathVariable("orderId") Long orderId, Model model) {
// method implementation
}
}
The @RequestMapping allows using regular expressions in the pattern string, as well. This allows to put a very basic validation check in the input value.
In the following example, Spring will ensure that the ‘year‘ is a 4-digit number and ‘month‘ is a 2-digit number. If values are correct then Spring maps them to the respective parameters. If not, then URL is not matched whci may result into 404 error.
@RequestMapping("/view/{year:\\d{4}}/{month:\\d{2}}")
public String viewArticle(@PathVariable("year") int year,
@PathVariable("month") int month, Model model) {
// method implementation
}
4. Mapping Request Parameters and Headers
When using @RequestMapping annotation, we can use the following annotations to handle the request parameters and headers:
Annotation | Purpose |
---|---|
@RequestParam | Maps the request parameters or query parameters |
@RequestHeader | Maps the request headers |
In the following example, we can invoke the URLs /search/results
or /search/results?query=spring
. Both will work because the query parameter is optional.
In the second method, Spring maps the Client-Id
and Client-Secret
request headers to the respective parameters in the handler method. These patameters are mandatory. If we do not send these headers then Spring will throw a MissingRequestHeaderException.
@RequestMapping("/search/results")
public String search(@RequestParam(value = "query", required = false, defaultValue = "default") String query) {
// Logic to perform search based on query
return "searchResults";
}
@RequestMapping("/info")
public String getDataInfo(@RequestHeader("Client-Id") String clientId,
@RequestHeader("Client-Secret") String clientSecret, Model model) {
//Method implementation
}
5. Content Negotiation
The content negotiation is a mechanism for selecting the best representation of a resource based on client and server preferences such as XML or JSON. The @RequestMapping annotation allows to to specify the media types that a method can produce or consume using the attributes ‘produces‘ and ‘consumes‘.
- The client sends an
Accept
header in the HTTP request to indicate the media types it can accept. - The server uses the
Content-Type
header to specify the media type of the response it is sending.
In the following example:
- The
getProductAsJson
method will be invoked if the client acceptsapplication/json
. - The
getProductAsXml
method will be invoked if the client acceptsapplication/xml
.
@RequestMapping(value = "/product", produces = "application/json")
public Product getProductAsJson() {
//return data
}
@RequestMapping(value = "/product", produces = "application/xml")
public Product getProductAsXml() {
//return data
}
Drop me your comments/questions in comments section.
Happy Learning !!
Comments