Friday, 8 July 2011

Designing Spring 3 MVC Controller RequestMethod Handlers

When using Spring 3 MVC, you define a handler method in your controller using the @RequestMethod annotation. This annotation has four attributes, all well documented in the Spring javadoc, that are:
  • value - identifying the path mapping URL such as: /events/search.
  • method - The HTTP request method to map to: GET, POST, PUT, DELETE etc.
  • params - The request parameters, for example 'day=Tuesday' from a URL such as x/y/z?day=Tuesday.
  • headers - Details of the request header, for example 'content-type=text/*'.
The above attributes act as filtering conditions that are applied to a HTTP request, so that your handler method is called in the appropriate circumstances. For example, call a particular method when the request is a POST and the URL is x/y/z?day=Tuesday and it contains the header: ‘content-type=text/*’. Or, as demonstrated in the example code below, call the doCreateForm method to handle all requests where the method is GET and the URL is /search.

  @RequestMapping(value = "/search", method = RequestMethod.GET)
public String getCreateForm(Model model) {

Handler method signatures are particularly flexible and take a large number of different parameters in any order. The only fixed rule is that a validation result object such as Errors or BindingResults must follow the the command object to which it refers:

  @RequestMapping(value = "/search", method = RequestMethod.POST)
public String doSearch(SearchCriteria criteria, BindingResult bindingResult, Model model) {

A full list of parameters and possible return types is available in the Spring 3 Javadocs for @RequestMethod. From this documentation, you will see that you do have access to the usual servlet classes such as HttpServletRequest, but wisely, the on-line examples steer you away from using these kinds of objects in favour of simple Model based objects:

  @RequestMapping(method = RequestMethod.GET, params="day")
public String getAppointmentsForDay(@RequestParam @DateTimeFormat(iso=ISO.DATE) LocalDate day, Model model) {

I guess that as a rule, you should prefer using Models, command objects, @PathVariable and @RequestParam {value} to using Servlet HttpXXXXX classes.

Although not stated in the documentation, it seems to be convention that the command object bean is an input parameter, taking input from the previous POST or GET and that any Model parameter is an output parameter, which means that the usual basic method scenario should be something like:
  1. Read values from command object.
  2. Use these methods to do something (like access a database).
  3. Get your results and stuff them into the Model with an appropriate key if necessary.
  4. Return the name of your next View.
  5. Use the data from the model in your JSP.
There are several examples available but they don’t highlight the flexibility of this system especially in the area of the @RequestMapping annotation.

Links Example MVC Code

No comments: