I really love Spring MVC’s annotated controllers. They are compact and nice to use but in some cases, a bit of a mission to get working.

<form:select>

On a report page I am working on, the user needs to have the ability to sort the result by selecting the relevant column from a select box.

So step one, we need a controller with our form object on the model, and we need this controller to handle the GET requests.

 
@RequestMapping(method = RequestMethod.GET)
public String showPage(
        @RequestParam(value = "sort", required = false)
                String sortOption,
        @RequestParam(value = "order", required = false)
                String sortOrder,
        ModelMap model) {

  SearchHelper searchHelper = new SearchHelper(true,            
                          SortOptionMap.reportSortOptions, 
                          SortOptionMap.reportSortOptions_default);

  searchHelper.setSelectedSortOption(sortOption);
  searchHelper.setSelectedOrdering(sortOrder);

  model.addAttribute("command", searchHelper);

  model.put("products", repository.fetchProducts(sortOption, sortOrder));
  return getSuccessView();
}

Then we need another piece of the controller to handle the POST.

 
@RequestMapping(method = RequestMethod.POST)
public ModelAndView handleSubmit(
        @ModelAttribute("command")SearchHelper searchHelper,
        BindingResult result,
        SessionStatus status,
        ModelMap model) {

  status.setComplete();

  return new ModelAndView(
        new RedirectView(getSuccessView()+searchHelper.getUrl(), true), model);
}

What is the SearchHelper you ask?

 
public class SearchHelper {
	private boolean ascending;
	private Map sortOptionMap;
	private Map sortOrderMap;
	private String selectedSortOption;
	private String selectedSortOrder;
    //getters and setters
}

It’s just a little helper class to keep search and sort functionality together. It might be an overarchitected Friday idea, but I haven’t decided yet.

And the last piece is the JSP.

 

    
        
            
        
    
    
        
            
        
    
    

What I figured out

While it seems really obvious now, it took a while to work out that the path for the select item must refer to an object that is the same type as the type of the value in the option tag. If you get this wrong, there is no error generated either, it just doesn’t work.

If you want to call the form backing object anything other than “command” you need to let the form know. The easiest solution is to leave it as “command” because in the POST you can see that it will understand that the “command” is really a SearchHelper object.

So…

I still think annotated controllers are worth the effort. Look at how few lines I will have to test!