Typically, in Spring MVC, we write a controller class to handle requests from clients. The controller then calls the business class to handle the business-related tasks and redirects the client to the logical view name, which is resolved by Spring’s scheduler Servlet to render the result or output.
This completes the round trip of a typical request-response cycle.
Today I have compiled 14 tips for writing Spring MVC controllers. Did you get them today? (≧ del ≦) /
1. Use the @controller stereotype
This is the easiest way to create a controller class that can handle one or more requests. Just by annotating a class @Controller with a stereotype, for example:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeController { @RequestMapping("/") public String visitHome() { return "home"; }}Copy the code
As you can see, the visitHome() method handles requests from the application context path (/) by redirecting to a view named Home.
Note: The @Controller prototype can only be used when the annotation driver is enabled in Spring’s configuration file:
<annotation-driven />
Copy the code
When the annotation driver is enabled, the Spring container automatically scans for classes under the package specified in the following statements:
<context:component-scan base-package="net.codejava.spring" />
Copy the code
Classes annotated by the @Controller annotation are configured as controllers. This is most desirable because it is simple: there is no need to declare beans for the controller in the configuration file.
Note: By using the @Controller annotation, you can have a multi-action Controller class that can handle multiple different requests. Such as:
@Controller
public class MultiActionController {
@RequestMapping("/listUsers")
public ModelAndView listUsers() {
}
@RequestMapping("/saveUser")
public ModelAndView saveUser(User user) {
}
@RequestMapping("/deleteUser")
public ModelAndView deleteUser(User user) {
}
}
Copy the code
As you can see in the controller class above, there are three different types of requests handled by three methods: /listUsers, /saveUser, and /deleteUser respectively.
2. Realize the controller interface
Another (perhaps classic) way to create a Controller in Spring MVC is to have a class implement the Controller interface. Such as:
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"); }}Copy the code
The implementation class must override the handleRequest() method, which will be called by the Spring scheduler Servlet when a match request comes in. The request URL pattern handled by this controller is defined in the Spring context configuration file as follows:
<bean name="/main" class="net.codejava.spring.MainController" />
Copy the code
However, the disadvantage of this approach is that the controller class cannot handle multiple request urls.
3. Extend AbstractController class
If you want easy control over supported HTTP methods, session and content caching. Extending your controller AbstractController class is ideal. Consider the following example:
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");
}
}
Copy the code
This creates a single-action controller with configurations for supported methods, sessions, and caches, which can then be specified in the bean declaration of the controller. Such as:
<bean name="/big" class="net.codejava.spring.BigController">
<property name="supportedMethods" value="POST"/>
</bean>
Copy the code
This configuration indicates that the Hander method that posts this controller supports only this method.
Spring MVC also provides several controller classes designed for specific purposes, including:
- AbstractUrlViewController
- MultiActionController
- ParameterizableViewController
- ServletForwardingController
- ServletWrappingController
- UrlFilenameViewController
4. Specify the URL mapping for the handler methods
This is mandatory when coding a controller class designed to handle one or more specific requests. Spring MVC provides the @requestMapping annotation, which specifies the URL mapping. Such as:
@RequestMapping("/login")
Copy the code
This maps the URL pattern for /login to be handled by an annotated method or class. When this annotation is used at the class level, the class becomes a single-action controller. Such as:
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"; }}Copy the code
When the @requestMapping annotation is used at the method level, you can have a multi-action controller. Such as:
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"; }}Copy the code
The @RequestMapping annotation can also be used to specify multiple URL schemas to be handled by a method. Such as:
@RequestMapping({"/hello", "/hi", "/greetings"})
Copy the code
In addition, this annotation has other properties that may be useful in some cases, such as Method.
Specify HTTP request methods for handler methods
You can use the method attribute of the annotation to specify which HTTP methods (GET, POST, PUT, etc.) are supported by the handler method @requestMapping. Here’s an example:
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"; }}Copy the code
This controller has two methods /login that handle the same URL pattern, but the former is used for the GET method and the latter for the POST method. For more information about using the @RequestMapping annotation, see the @RequestMapping Annotation.
6. Map request parameters to handler methods
One of the cool features of Spring MVC is that you can use the @RequestParam annotation to retrieve request parameters as regular arguments to handler methods. This is a good way to separate the controller HttpServletRequest from the interface of the Servlet API.
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(@RequestParam String username,
@RequestParam String password) {
}
Copy the code
Spring binds method parameters username and password to HTTP request parameters with the same name. This means that you can call the URL as follows (if the request method is GET) :
http://localhost: 8080 / spring/login? Username = scott&password = tigerCopy the code
Type conversions are also automated. For example, if you declare integer as a parameter of the following type:
@RequestParam int securityNumber
Copy the code
Spring then automatically converts the value of the request parameter (string) to the specified type (integer) in the handler method.
If the parameter name is different from the variable name, the actual parameter name can be specified as follows:
@RequestParam("SSN") int securityNumber
Copy the code
The @RequestParam annotation also has two additional attributes, which may be useful in some cases. This property specifies whether the parameter is required. For example: the required
@RequestParam(required = false) String country
Copy the code
This means that the parameter country is optional; Therefore, it may be lost from the request. In the example above, country if no such argument exists in the request, the variable will be null.
Another attribute is defaultValue, which can be used as a fallback value if the request parameter is null. Such as:
@RequestParam(defaultValue = "18") int age
Copy the code
Map If the method argument is type, Spring also allows us to access all parameters as objects Map<String, String>. Such as:
doLogin(@RequestParam Map<String, String> params)
Copy the code
The mapping parameters then contain all the request parameters in the form of key-value pairs. For more information about using @RequestParam annotations, see @RequestParam Annotations.
7. Return to model and view
Once the business logic is processed, the handler method should return a view, which is then parsed by Spring’s scheduler servlet. Spring allows us to return a String or object from a ModelAndView from a handler method.
In the following example, the handler method returns a String and represents a view named LoginForm:
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String viewLogin() {
return "LoginForm";
}
Copy the code
This is the easiest way to return the view name. However, if you want to send additional data to the view, you must return a ModelAndView object. Consider the following handler methods:
@RequestMapping("/listUsers") public ModelAndView listUsers() { List<User> listUser = new ArrayList<>(); // Get the user list from the DAO... ModelAndView modelView = new ModelAndView("UserList"); modelView.addObject("listUser", listUser); return modelView; }Copy the code
As you can see, this handler method returns a ModelAndView holding a User object with the view name UserList and a collection of objects that can be used in the view.
Spring is also very flexible because you can declare a ModelAndView object as a parameter to a handler method instead of creating a new object. Therefore, the above example can be rewritten as follows:
@RequestMapping("/listUsers") public ModelAndView listUsers(ModelAndView modelView) { List<User> listUser = new ArrayList<>(); // Get the user list from the DAO... modelView.setViewName("UserList"); modelView.addObject("listUser", listUser); return modelView; }Copy the code
For more information about this class, see: ModelAndView Class.
8. Put objects into the model
In an application that follows an MVC architecture, the controller (C) should pass the data to the model (M), which is then used in the view (V). As we saw in the previous example, the addObject() method of this class, ModelAndView, puts objects into the model as name-value pairs:
modelView.addObject("listUser", listUser);
modelView.addObject("siteName", new String("CodeJava.net"));
modelView.addObject("users", 1200000);
Copy the code
Again, Spring is very flexible. You can declare type parameters in a Map handler method. Spring uses this mapping to store objects for the model. Let’s look at another example:
@RequestMapping(method = RequestMethod.GET)
public String viewStats(Map<String, Object> model) {
model.put("siteName", "CodeJava.net");
model.put("pageviews", 320000);
return "Stats";
}
Copy the code
This is simpler than using a ModelAndView object. Depending on your preference, you can use a Map or use a ModelAndView object. Thank you for Spring’s flexibility.
Redirection in handler methods
Redirect :/ Append before the URL if you want to redirect the user to another URL if conditions are met. The following code snippet gives an example:
// Check login status.... if (! isLogin) { return new ModelAndView("redirect:/login"); } // Return to the user listCopy the code
In the above code, /login if not logged in, the user will be redirected to that URL.
10. Handle form submission and validation
Spring makes it easy to handle form submissions by providing @ModelAttribute annotations for binding form fields to form-supporting objects and BindingResult interfaces for validating form fields. The following code snippet shows a typical handler method responsible for processing and validating form data:
@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 error} // registration process...... return "Success"; }}Copy the code
Learn more about the @ModelAttribute annotation and the BindingResult interface from Spring’s official documentation:
- Use @modelAttribute on method parameters
- Use @modelAttribute on methods
- Interface binding Result
11. Handle file upload
Spring also makes it easy to handle file uploads in handler methods by automatically binding upload data to the CommonsMultipartFile object array. Spring uses Apache Commons FileUpload as a basic multipart parser.
The following code snippet shows how easy it is to upload files from the client
@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST) public String handleFileUpload( @RequestParam CommonsMultipartFile[] fileUpload) throws Exception { for (CommonsMultipartFile aFile : FileUpload) {/ / store the uploaded files aFile. TransferTo (new File (aFile. GetOriginalFilename ())); } return "Success"; }Copy the code
12. Automatically assemble business classes in the controller
The controller should delegate the processing of the business logic to the relevant business class. To do this, you can use the @AutoWired annotation to have Spring automatically inject the actual implementation of the business class into the controller.
Consider the following code snippet for the controller class:
@Controller public class UserController { @Autowired private UserDAO userDAO; Public String listUser() {userdao.list (); } public String saveUser(User User) {userdao.save (User); } public String deleteUser(User User) {userdao.delete (User); } public String getUser(int userId) {userdao.get (userId); }}Copy the code
At this point, all business logic related to user management is provided by the implementation of the UserDAO interface. Such as:
interface UserDAO {
List<User> list();
void save(User user);
void checkLogin(User user);
}
Copy the code
For more information about @Autowired annotations, see Annotation Type autowiring.
13. Access HttpServletRequest and HttpServletResponse
In some cases, you need to access the HttpServletRequest or HttpServletResponse object directly in the handler method.
With Spring’s flexibility, you can simply add parameters to the processing method. Such as:
@RequestMapping("/download") public String doDownloadFile( HttpServletRequest request, HttpServletResponse Response) {// Access request // access response return "DownloadPage"; }Copy the code
Spring detects and automatically injects HttpServletRequest and HttpServletResponse objects into methods. You can then access requests and responses such as getting an InputStream, OutputStream, or returning a specific HTTP code.
14. Follow the principle of single responsibility
Finally, there are two good practices you should follow when designing and writing Spring MVC controllers:
1) The controller class should not execute business logic. Instead, it should delegate business processing to the relevant business class. This keeps the controller focused on its design responsibility to control the workflow of the application. Such as:
@Controller public class UserController { @Autowired private UserDAO userDAO; public String listUser() { userDAO.list(); } public String saveUser(User user) { userDAO.save(user); } public String deleteUser(User user) { userDAO.delete(user); } public String getUser(int userId) { userDAO.get(userId); }}Copy the code
2) Create each individual controller for each business domain. For example, UserController is used to control the OrderController workflow for user management, the OrderController workflow for controlling order processing, and so on. Such as:
@Controller
public class UserController {
}
@Controller
public class ProductController {
}
@Controller
public class OrderController {
}
@Controller
public class PaymentController {
}
Copy the code
Here are 14 tips to help you write your controller classes correctly and efficiently in Spring MVC. If you have other tips or suggestions, feel free to share your thoughts in the comments.