Sunday, November 26, 2023

How Request mapping or HandlerMapping works in Spring MVC? @RequestMapping Example

Hello guys, In last a couple of articles, we have learned how Spring MVC framework works and what is the role of DispatcherServlet in Spring MVC. We have briefly touched another frequently asked Spring MVC interview question, how does requests are mapped to controllers in Spring MVC? In this article, we'll expand our knowledge on that. You have learned that DispatcherServlet is the front controller in Spring MVC framework, it is the single point entry and all incoming request goes through it, but instead of processing those request it just dispatches the request to the appropriate handler methods based on the request mapping, but how does it do that?

In this article, you'll learn how DispatcherServlet finds the appropriate controller or handler method for a web request in Spring MVC. In order to interpret the mappings defined in the request mapping, DispatcherServlet needs a HandlerMapping implementation (org.springframework.web.servlet.HandlerMapping). 

When a web request comes the DispatcherServlet consults with one or more HandlerMapping implementations to find out which controller (handler) can handle the request. In short, it's the HandlerMapping that determines which controller to call.

The HandlerMapping interface of Spring MVC framework provides the abstraction for mapping requests to handlers. The HandlerMapping implementations are capable of inspecting the request and coming up with an appropriate controller. 

Spring MVC provides many built-in HandlerMapping implementations, and the most popular of them is the @RequestMapping annotation which is the RequestMappingHandlerMapping class. 

In order to use the @RequestMapping annotation or RequestMappingHandlerMapping, you have to add the element in our web application context configuration file. Alternatively, you can also annotated your @Configuration class with @EnableWebMvc annotation. 

Before annotation, you might remember that Spring MVC controllers used to extend AbstractController and override handleRequestInternal(HttpServletRequest request, HttpServletResponse response) method which returns ModelAndView object but from Spring 2.5 onwards you can just use @Controller to annotate a Spring MVC controller. 

Though, @Controller is just for component scanning, actual request mapping is done by using @RequestMapping annotation.  This annotation allows you to map HTTP request based upon their path, query parameters, headers and method type to handler methods of Controllers, which are actually responsible for processing request and returning response. 



For example, suppose your website has a "contact" page then you can create a ContactController like below to process any request coming to "/contact" URL:

@Controller
@RequestMapping("/contact")
public class ContactController {

    @RequestMapping(method = GET)
    public String contact(Model model) {
        model.addAttribute("email", "job@example.com");
        return "contact"
        l
    }

}

You can see that contact() is your handler method which will handle all request to "/contact" URL. It return a logical view name "contact" which is resolve to /WEB-INF/contact.jsp using ViewResolver. 

The @RequestMapping annotation is very powerful and gives you several features for sophisticated request mapping. 

For example, you can map request based upon HTTP method as shown above. You can also map multiple URLs to same handler method because the value attribute of @RequestMapping annotation can accept a String array as shown below:

@RequestMapping({
    "/contact",
    "/about",
    "/me"
})
public class ContactController {

    @RequestMapping(method = GET)
    public String contact(Model model) {
        model.addAttribute("email", "job@example.com");
        return "contact"
        l
    }

}

In above example, web requests to "/contact", "/about", and "/me" will all goes to contact() method but only for GET request. If there is any POST request then that will not come into this Controller class because just declaring @RequestMapping at class level is not enough for request mapping, you also need to declare @RequestMapping annotation at the method level. 

Any method inside Controller class with is not annotated using @RequestMapping annotation will be ignored by Spring MVC. 

Btw, you can also use @RequestMapping annotation to map request based upon query parameters as shown below. 

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/example")
public class ExampleController {

    // Mapping based on a single query parameter
    @GetMapping("/byParam")
    public String handleRequestByParam(@RequestParam("name") String name) {
        return "Hello, " + name + "!";
    }

    // Mapping based on multiple query parameters
    @GetMapping("/byParams")
    public String handleRequestByParams(
            @RequestParam("firstName") String firstName,
            @RequestParam("lastName") String lastName) {
        return "Hello, " + firstName + " " + lastName + "!";
    }

    // Mapping with default values for query parameters
    @GetMapping("/withDefault")
    public String handleRequestWithDefault(
            @RequestParam(value = "name", defaultValue = "Guest") String name) {
        return "Hello, " + name + "!";
    }
}

In this example:

The @RestController annotation is used to indicate that this class is a controller.
The @RequestMapping("/example") annotation at the class level specifies the base path for all mappings in this controller.
The @GetMapping annotation is used to handle HTTP GET requests.
The @RequestParam annotation is used to bind query parameters to method parameters.
You can test these mappings using URLs like:

/example/byParam?name=John
/example/byParams?firstName=John&lastName=Doe
/example/withDefault (This will use the default value "Guest" if the name parameter is not provided.)
Make sure to adapt the code according to your specific use case and requirements.

That's all about how request is mapped to controller in Spring MVC framework. We have also see example of @RequestMapping annotation in Spring MVC. The DispatcherServlet uses HandlerMapping implementation to find the appropriate controller for web requests. One of the popular implementation of HandlerMapping is RequestMappingHandlerMapping which powers @RequestMapping annotation. 

This annotation allows you to map http request based upon URL, query parameters, headers and http methods. You can also map multiple URLs to same controller method. 

Other Spring Framework articles you may like to explore 

Thanks for reading this article so far. If you like my explanation of how DispatcherServlet map request to controller in Spring MVC framework then please share with your friends and colleagues. If you have any question or feedback then please drop a comment and I'll try to find an answer for you.

No comments :

Post a Comment