14 Tips for Writing Spring MVC Controller

Details Written by Nam Ha Minh Last Updated on 20 June 2019 | Print Email

@Controller

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"; } }

visitHome()

NOTE:

@Controller

<annotation-driven />

<context:component-scan base-package="net.codejava.spring" />

@Controller

NOTE:

@Controller

@Controller public class MultiActionController { @RequestMapping("/listUsers") public ModelAndView listUsers() { } @RequestMapping("/saveUser") public ModelAndView saveUser(User user) { } @RequestMapping("/deleteUser") public ModelAndView deleteUser(User user) { } }

Controller

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"); } }

handleRequest()

<bean name="/main" class="net.codejava.spring.MainController" />

AbstractController

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"); } }

<bean name="/big" class="net.codejava.spring.BigController"> <property name="supportedMethods" value="POST"/> </bean>

@RequestMapping

@RequestMapping("/login")

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"; } }

@RequestMapping

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"; } }

@RequestMapping

@RequestMapping({"/hello", "/hi", "/greetings"})

method

@RequestMapping

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"; } }

@RequestMapping

@RequestParam

HttpServletRequest

@RequestMapping(value = "/login", method = RequestMethod.POST) public String doLogin(@RequestParam String username, @RequestParam String password) { }

username

password

In this article, I'm going to share with you some fundamental techniques and good practices involve in writing controller class with Spring MVC framework . Typically in Spring MVC, we write a controller class to handle requests coming from the client. Then the controller invokes a business class to process business-related tasks, and then redirects the client to a logical view name which is resolved by the Spring’s dispatcher servlet in order to render results or output. That completes a round trip of a typical request-response cycle.Here are summary of the tips you will learn throughout this article:This is the simplest way for creating a controller class to handle one or multiple requests. Just by annotating a class with thestereotype, for example:As you can see, themethod handles requests coming to the application’s context path (/) by redirecting to the view namedthestereotype can only be used with annotation-driven is enabled in the Spring’s configuration file:When annotation-driven is enabled, Spring container automatically scans for classes under the package specified in the following statement:The classes annotated by theannotation are configured as controllers. This is the most preferable way because its simplicity: no need to declare beans for controllers in the configuration file.By using theannotation, you can have a multi-actions controller class that is able to serve multiple different requests. For example:As you can see in the above controller class, there are 3 handler methods that processes 3 different requestsand, respectively.Another (and maybe classic) way of creating a controller in Spring MVC is having a class implemented theinterface. For example:The implementing class must override themethod which will be invoked by the Spring dispatcher servlet when a matching request comes in. The request URL pattern handled by this controller is defined in the Spring’s context configuration file as follows:However, a drawback of this approach is the controller class cannot handle multiple request URLs.Having your controller class extended theclass if you want to easily control the supported HTTP methods, session and content caching. Consider the following example:This creates a single-action controller with configurations regarding supported methods, session and caching can be specified in the bean declaration of the controller. For example:This configuration indicates that the only POST method is supported by this controller’s hander method. For other configuration (session, caching) see: AbstractController .Spring MVC also offers several controller classes which are designed for specific purposes: AbstractUrlViewController 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 theannotation which is used for specifying URL mapping. For example:That maps the URL patternto be handled by the annotated method or class. When this annotation is used at class level, the class becomes a single-action controller. For example:When theannotation is used at method level, you can have a multi-action controller. For example:Theannotation can be also used for specifying multiple URL patterns to be handled by a single method. For example:In addition, this annotation has other properties which may be useful in some cases, e.g. theproperty which is covered next.You can specify which HTTP method (GET, POST, PUT,…) is supported by a handler method by using theproperty of theannotation. Here’s an example:As you can see, this controller has two methods that handle the same URL pattern, but the former is for GET method and the latter is for POST method.For more information about using theannotation, see: @RequestMapping annotation One of cool features of Spring MVC is that, you can retrieve request parameters as regular parameters of the handler method by using theannotation. This is a good way to decouple the controller from theinterface of Servlet API.Let’s see various examples. Consider the following method:Spring binds the method parametersandto the HTTP request parameters with the same names. That means you can invoke a URL as follows (if request method is GET):

http://localhost:8080/spring/login?username=scott&password=tiger

@RequestParam int securityNumber

@RequestParam("SSN") int securityNumber

@RequestParam

required

@RequestParam(required = false) String country

defaultValue

@RequestParam(defaultValue = "18") int age

Map

Map<String, String>.

doLogin(@RequestParam Map<String, String> params)

params

@RequestParam

String

ModelAndView

@RequestMapping(value = "/login", method = RequestMethod.GET) public String viewLogin() { return "LoginForm"; }

ModelAndView

@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; }

ModelAndView

User

ModelAndView

@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; }

ModelAndView

addObject()

ModelAndView

modelView.addObject("listUser", listUser); modelView.addObject("siteName", new String("CodeJava.net")); modelView.addObject("users", 1200000);

Map

@RequestMapping(method = RequestMethod.GET) public String viewStats(Map<String, Object> model) { model.put("siteName", "CodeJava.net"); model.put("pageviews", 320000); return "Stats"; }

ModelAndView

ModelAndView

redirect:/

// check login status.... if (!isLogin) { return new ModelAndView("redirect:/login"); } // return a list of Users

@ModelAttribute

BindingResult

@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"; } }

@ModelAttribute

BindingResult

CommonsMultipartFile

@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"; }

@Autowired

@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); } }

UserDAO

interface UserDAO { List<User> list(); void save(User user); void checkLogin(User user); }

@Autowired

List<User> listUser = userDAO.list();

@Autowired

HttpServletRequest

HttpServletResponse

@RequestMapping("/download") public String doDownloadFile( HttpServletRequest request, HttpServletResponse response) { // access the request // access the response return "DownloadPage"; }

HttpServletRequest

HttpServletResponse

InputStream

OutputStream

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: @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: @Controller public class UserController { } @Controller public class ProductController { } @Controller public class OrderController { } @Controller public class PaymentController { }

Other Spring Tutorials:



About the Author: Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on





is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.

Add comment

Type conversion is also done automatically. For example, if you declare a parameter of typeas follows:Then Spring will automatically convert value of the request parameter (String) to the specified type (integer) in the handler method.In case the parameter name is different than the variable name. You can specify actual name of the parameter as follows:Theannotation also has additional 2 attributes which might be useful in some cases. Theattribute specifies whether the parameter is mandatory or not. For example:That means the parameteris optional, hence can be missing from the request. In the above example, the variablewill be null if there is no such parameter present in the request.Another attribute is, which can be used as a fallback value when the request parameter is empty. For example:Spring also allows us to access all parameters as aobject if the method parameter is of typeFor example:Then the mapcontains all request parameters in form of key-value pairs.For more information about using theannotation, see: @RequestParam annotation.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 aor aobject from the hander method. In the following example, the handler method returns a String represents a view named “LoginForm”:That’s the simplest way of returning a view name. But if you want to send additional data to the view, you must return aobject. Consider the following handler method:As you can see, this handler method returns aobject that holds the view name “UserList” and a collection ofobjects which can be used in the view.Spring is also very flexible, as you can declare theobject as a parameter of the handler method instead of creating a new one. Thus, the above example can be re-written as follows:You can learn more about theclass by visiting: ModelAndView class 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, themethod of theclass is for putting an object to the model, in form of name-value pair:Again, Spring is very flexible. You can declare a parameter of typein the handler method, Spring uses this map to store objects for the model. Let’s see another example:This is even simpler than usingobject. Depending on your taste, you can use either Map orobject. Thanks for the flexibility of Spring.In case you want to redirect the user to another URL if a condition is met, just appendbefore the URL. The following code snippet gives an example:In the above code, the user will be redirected to theURL if he is not logged in.Spring makes it easy to handle form submission, by providing theannotation for binding form fields to a form backing object, and theinterface for validating form fields. The following code snippet shows a typical handler method that is responsible for handling and validating form data:Learn more about theannotation and theinterface from Spring’s official documentation:You can learn more and in-depth about form handling and form validation in Spring MVC by reading Spring MVC Form Handling Tutorial and Spring MVC Form Validation Tutorial Spring also makes it easy to handle file upload within a handler method, by automatically binding upload data to an array ofobjects. 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:You can learn the complete solution for handling file upload with Spring MVC by following the Spring MVC File Upload Tutorial A controller should delegate the processing of business logic to relevant business classes. For this purpose, you can use theannotation to let Spring automatically injects actual implementation of a business class to the controller. Consider the following code snippet of a controller class:Here, all the business logics related to User management is provided by an implementation of theinterface. For example:By using theannotation, the handler methods can delegate tasks to the business class, as we can see in the above example:For more information about theannotation, see: Annotation Type Autowired In some cases, you need to directly access theorobjects within a handler method. By the flexibility of Spring, just add relevant parameter to the handler method. For example:Spring detects and automatically injects theandobjects into the method. Then you can access the request and response such as gettingor returning a specific HTTP code.Finally, there are two good practices you should follow when designing and coding controllers in Spring MVC:So far Ihave shared 14 tips that help you write controller classes in Spring MVC properly and efficiently. However that’s not the end. If you have other tips or suggestions, feel free to share your thoughts. If you want to fully learn Spring framework, I recommend you to read this Pro Spring 5 book, or take this Spring Master Class course on Udemy.