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 using HandlerMappings.
- 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 as GET, 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, accessing http://localhost:8080/ would lead to a display of the view, index.jsp file. Note the controller class HealthApplication.
@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, accessing http://localhost:8080/ will print Hello 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 as http://localhost:8080/account/ is accessed, one will be taken to the login page. Note that a URL such as http://localhost:8080/account (without trailing "/") would result in an error. The point to note is that the login method does not have URL mapping with the RequestMapping 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 as http://localhost:8080/account/signup is accessed, the signup page is displayed. Similar is the case with the URL http://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 method login:
@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.