Before we go into the details of understanding the different aspects of implementing the controllers, let's quickly go over how controllers take part in the MVC workflow.
The following is the workflow representing the processing of a web request and the response by a controller:
- The requests are first intercepted by the Dispatcher servlet.
- The Dispatcher servlet does the initial stage of request processing by resolving locale/themes, performing activities such as taking snapshots of the request attributes, and making framework objects available to handlers and view objects.
- Once the initial processing is done as mentioned in the preceding step, an appropriate handler is determined and invoked for further processing the request. It is the
handleRequest
method that is invoked on the handler instance, which, in turn, invokes the appropriate method on the appropriate controller determined usingHandlerMappings
. - The controller then processes the request, and returns an instance of
ModelAndView
appropriately. - The instance of
ModelAndView
is further processed by the Dispatcher servlet to send out the response to the user.
Let us start building the sample healthcare app for doctors and patients. This app will be used to illustrate the controllers' implementations with multiple examples. In this section, we will see how to implement the controllers for handling users' requests for accessing the home page, signup form, login form, and so on. In the previous section, we have seen how to build a Hello World web app using Spring Boot. We will start implementing controllers using the Spring Boot app.
The following are the different controllers which are used to process requests for accessing the home page, signup form, and login page:
UserAccountController
RxController
DoctorSearchController
We will see the implementation of the preceding controllers in code examples listed as follows. In the most trivial form, controller classes can be implemented in the following manner:
- The
controller
class can be annotated with@Controller
or@RestController
annotations at the class level. The code samples given below represent the usage of both types of annotations.@RestController
is used as a convenience annotation to represent the annotations such as@Controller
and@ResponseBody
. When used at the class level, the controller can serve REST API requests. - When using the
@Controller
or@RestController
annotation, request mappings can be provided using one of the following techniques:- Using RequestMapping Annotation at Method Level: The following code represents the
RequestMapping
annotation at the method level,home()
. Spring framework 4.3 introduced annotations such as@GetMapping
,@PostMapping
,@PutMapping
, and so on to simplify mappings for common HTTP method types such asGET
,POST
,PUT
, and so on respectively. These new annotations enhance code readability. In the following code, the aforementioned annotations have been used interchangeably for providing greater clarity and ease of understanding. When the application is started, accessinghttp://localhost:8080/
would lead to a display of the view,index.jsp
file. Note thecontroller
classHealthApplication
.
- Using RequestMapping Annotation at Method Level: The following code represents the
@Controller @SpringBootApplication public class HealthApplication { @RequestMapping("/") String home() { return "index"; } public static void main(String[] args) { SpringApplication.run(HelloWorldApplication.class, args); } }
In the code given next, the
@GetMapping
annotation is used in place of@RequestMapping
, as shown in the preceding code sample.GetMapping
is a composed annotation which acts as a shortcut for@RequestMapping
(method = RequestMethod.GET
). When the application is started, accessinghttp://localhost:8080/
will printHello world. This is a health application!
.
@RestController @SpringBootApplication public class HealthApplication { @GetMapping("/") String home() { return "Hello world. This is a health application!"; } public static void main(String[] args) { SpringApplication.run(HelloWorldApplication.class, args); } }
- Using RequestMapping Annotation at both, Method & Class Level: The following code represents
RequestMapping
at both the class and the method level. When the URL such ashttp://localhost:8080/account/
is accessed, one will be taken to the login page. Note that a URL such ashttp://localhost:8080/account
(without trailing "/") would result in an error. The point to note is that thelogin
method does not have URL mapping with theRequestMapping
annotation. This, primarily, acts as a catch--all method to handle all the requests with different paths represented by using "/*
" (defined at the class level) except/account/
. When a URL such ashttp://localhost:8080/account/signup
is accessed, the signup page is displayed. Similar is the case with the URLhttp://localhost:8080/account/forgotpassword
which would open up the forgot password page.
@Controller @RequestMapping("/account/*") public class UserAccountController { @RequestMapping public String login() { return "login"; } @GetMapping("/signup") public String signup() { return "signup"; } @GetMapping("/forgotpassword") public String forgotpassword() { return "forgotpassword"; } }
- Using RequestMapping Annotations with Http Requests Type: In the following example, the HTTP request type
Get
is mapped to the methodlogin
:
@Controller @RequestMapping("/account/login") public class LoginController { // // @GetMapping can as well be used // @RequestMapping(method = RequestMethod.GET) public String login() { return "login"; } }
In the next section, we will learn the concepts and examples of handling request parameters in relation to handling forms such as signup, login, and so on as discussed in this section.