- Using the @Controller stereotype
- Implementing the Controller Interface
- Extending the AbstractController Class
- Specifying URL Mapping for Handler Method
- Specifying HTTP Request Methods for Handler Method
- Mapping Request Parameters to Handler Method
- Returning Model And View
- Putting Objects into the Model
- Redirection in Handler Method
- Handling Form Submission and Form Validation
- Handling File Upload
- Autowiring Business Classes in the Controller
- Accessing HttpServletRequest and HttpServletResponse
- Following the Single Responsibility Principle
1. Using the @Controller stereotype
This is the simplest way for creating a controller class to handle one or multiple requests. Just by annotating a class with the @Controller stereotype, for example:1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeController { @RequestMapping ( "/" ) public String visitHome() { // do something before returning view name return "home" ; } } |
1 | < annotation-driven /> |
1 | < context:component-scan base-package = "net.codejava.spring" /> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Controller public class MultiActionController { @RequestMapping ( "/listUsers" ) public ModelAndView listUsers() { } @RequestMapping ( "/saveUser" ) public ModelAndView saveUser(User user) { } @RequestMapping ( "/deleteUser" ) public ModelAndView deleteUser(User user) { } } |
2. Implementing the Controller Interface
Another (and maybe classic) way of creating a controller in Spring MVC is having a class implemented the Controller interface. For example:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class MainController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println( "Welcome main" ); return new ModelAndView( "main" ); } } |
1 | < bean name = "/main" class = "net.codejava.spring.MainController" /> |
3. Extending the AbstractController Class
Having your controller class extended the AbstractController class if you want to easily control the supported HTTP methods, session and content caching. Consider the following example:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; public class BigController extends AbstractController { @Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println( "You're big!" ); return new ModelAndView( "big" ); } } |
1 2 3 | < bean name = "/big" class = "net.codejava.spring.BigController" > < property name = "supportedMethods" value = "POST" /> </ bean > |
4. Specifying URL Mapping for Handler Method
This is the mandatory task you must do when coding a controller class which is designed for handling one or more specific requests. Spring MVC provides the @RequestMapping annotation which is used for specifying URL mapping. For example:1 | @RequestMapping("/login") |
1 2 3 4 5 6 7 8 9 10 11 12 13 | import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping ( "/hello" ) public class SingleActionController { @RequestMapping (method = RequestMethod.GET) public String sayHello() { return "hello" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class UserController { @RequestMapping ( "/listUsers" ) public String listUsers() { return "ListUsers" ; } @RequestMapping ( "/saveUser" ) public String saveUser() { return "EditUser" ; } @RequestMapping ( "/deleteUser" ) public String deleteUser() { return "DeleteUser" ; } } |
1 | @RequestMapping ({ "/hello" , "/hi" , "/greetings" }) |
5. Specifying HTTP Request Methods for Handler Method
You can specify which HTTP method (GET, POST, PUT,…) is supported by a handler method by using the method property of the @RequestMapping annotation. Here’s an example:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class LoginController { @RequestMapping (value = "/login" , method = RequestMethod.GET) public String viewLogin() { return "LoginForm" ; } @RequestMapping (value = "/login" , method = RequestMethod.POST) public String doLogin() { return "Home" ; } } |
6. Mapping Request Parameters to Handler Method
One of cool features of Spring MVC is that, you can retrieve request parameters as regular parameters of the handler method by using the @RequestParam annotation. This is a good way to decouple the controller from the HttpServletRequest interface of Servlet API. Let’s see various examples. Consider the following method:1 2 3 4 5 | @RequestMapping (value = "/login" , method = RequestMethod.POST) public String doLogin( @RequestParam String username, @RequestParam String password) { } |
http://localhost:8080/spring/login?username=scott&password=tiger
Type conversion is also done automatically. For example, if you declare a parameter of type integer as follows:1 | @RequestParam int securityNumber |
1 | @RequestParam ( "SSN" ) int securityNumber |
1 | @RequestParam (required = false ) String country |
1 | @RequestParam (defaultValue = "18" ) int age |
1 | doLogin( @RequestParam Map<String, String> params) |
7. Returning Model And View
After business logic is processed, a handler method should return a view which is then resolved by the Spring’s dispatcher servlet. Spring allows us to return either a String or a ModelAndView object from the hander method. In the following example, the handler method returns a String represents a view named “LoginForm”:1 2 3 4 | @RequestMapping (value = "/login" , method = RequestMethod.GET) public String viewLogin() { return "LoginForm" ; } |
1 2 3 4 5 6 7 8 9 10 11 | @RequestMapping ( "/listUsers" ) public ModelAndView listUsers() { List<User> listUser = new ArrayList<>(); // get user list from DAO... ModelAndView modelView = new ModelAndView( "UserList" ); modelView.addObject( "listUser" , listUser); return modelView; } |
1 2 3 4 5 6 7 8 9 10 11 | @RequestMapping ( "/listUsers" ) public ModelAndView listUsers(ModelAndView modelView) { List<User> listUser = new ArrayList<>(); // get user list from DAO... modelView.setViewName( "UserList" ); modelView.addObject( "listUser" , listUser); return modelView; } |
8. Putting Objects into the Model
In an application that follows the MVC architecture, the controller (C) should pass data into the model (M) which is then used in the view (V). As we see in the previous example, the addObject() method of the ModelAndView class is for putting an object to the model, in form of name-value pair:1 2 3 | modelView.addObject( "listUser" , listUser); modelView.addObject( "siteName" , new String( "CodeJava.net" )); modelView.addObject( "users" , 1200000 ); |
1 2 3 4 5 6 7 | @RequestMapping (method = RequestMethod.GET) public String viewStats(Map<String, Object> model) { model.put( "siteName" , "CodeJava.net" ); model.put( "pageviews" , 320000 ); return "Stats" ; } |
9. Redirection in Handler Method
In case you want to redirect the user to another URL if a condition is met, just append redirect:/ before the URL. The following code snippet gives an example:1 2 3 4 5 6 7 8 | // check login status.... if (!isLogin) { return new ModelAndView( "redirect:/login" ); } // return a list of Users |
10. Handling Form Submission and Form Validation
Spring makes it easy to handle form submission, by providing the @ModelAttribute annotation for binding form fields to a form backing object, and the BindingResult interface for validating form fields. The following code snippet shows a typical handler method that is responsible for handling and validating form data:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Controller public class RegistrationController { @RequestMapping (value = "/doRegister" , method = RequestMethod.POST) public String doRegister( @ModelAttribute ( "userForm" ) User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // form validation error } else { // form input is OK } // process registration... return "Success" ; } } |
11. Handling File Upload
Spring also makes it easy to handle file upload within a handler method, by automatically binding upload data to an array of CommonsMultipartFile objects. Spring uses Apache Commons FileUpload as the underlying multipart resolver. The following code snippet shows how easy it is to get files uploaded from the client:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @RequestMapping (value = "/uploadFiles" , method = RequestMethod.POST) public String handleFileUpload( @RequestParam CommonsMultipartFile[] fileUpload) throws Exception { for (CommonsMultipartFile aFile : fileUpload){ // stores the uploaded file aFile.transferTo( new File(aFile.getOriginalFilename())); } return "Success" ; } |
12. Autowiring Business Classes in the Controller
A controller should delegate the processing of business logic to relevant business classes. For this purpose, you can use the @Autowired annotation to let Spring automatically injects actual implementation of a business class to the controller. Consider the following code snippet of a controller class:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Controller public class UserController { @Autowired private UserDAO userDAO; public String listUser() { // handler method to list all users userDAO.list(); } public String saveUser(User user) { // handler method to save/update a user userDAO.save(user); } public String deleteUser(User user) { // handler method to delete a user userDAO.delete(user); } public String getUser( int userId) { // handler method to get a user userDAO.get(userId); } } |
1 2 3 4 5 6 7 8 | interface UserDAO { List<User> list(); void save(User user); void checkLogin(User user); } |
1 | List<User> listUser = userDAO.list(); |
13. Accessing HttpServletRequest and HttpServletResponse
In some cases, you need to directly access the HttpServletRequest or HttpServletResponse objects within a handler method. By the flexibility of Spring, just add relevant parameter to the handler method. For example:1 2 3 4 5 6 7 8 9 10 | @RequestMapping ( "/download" ) public String doDownloadFile( HttpServletRequest request, HttpServletResponse response) { // access the request // access the response return "DownloadPage" ; } |
14. Following the Single Responsibility Principle
Finally, there are two good practices you should follow when designing and coding controllers in Spring MVC:- A controller class should not execute business logic. Instead, it should delegate business processing to relevant business classes. This keeps the controller focusing on its designed responsibility is to control workflows of the application. For example:1234567891011121314151617181920212223242526
@Controller
public
class
UserController {
@Autowired
private
UserDAO userDAO;
public
String listUser() {
// handler method to list all users
userDAO.list();
}
public
String saveUser(User user) {
// handler method to save/update a user
userDAO.save(user);
}
public
String deleteUser(User user) {
// handler method to delete a user
userDAO.delete(user);
}
public
String getUser(
int
userId) {
// handler method to get a user
userDAO.get(userId);
}
}
- Create each separate controller for each business domain. For example, UserController for controlling workflows of the user management, OrderController for controlling workflows of order processing, etc. For example:1234567891011121314151617181920
@Controller
public
class
UserController {
}
@Controller
public
class
ProductController {
}
@Controller
public
class
OrderController {
}
@Controller
public
class
PaymentController {
}