Alex Rivera | Logout

Spring 3 MVC Handle multiple form submit with a single Controller

Asked 2011-01-31T11:01:43.743
9

Spring 3 MVC Handle multiple form submit with a Controller.

I am developing JSP page with multiple forms. 1) Search Customer, 2) Search Product, 3) Print Something etc. I've a different form bind object tied to each form and my controller code looks similar to below

  @Controller
  @RequestMapping(value="/search.do")
  public class SearchController {

    @RequestMapping(method = RequestMethod.GET)
    public String pageLoad(ModelMap modelMap) {
      modelMap.addAttribute("productSearch", new ProductSearchCriteria());
        modelMap.addAttribute("customerSearch", new CustomerSearchCriteria());
        modelMap.addAttribute("print", new PrintForm());
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView searchProducts(@ModelAttribute("productSearch") ProductSearchCriteria productSearchCriteria,
            BindingResult result, SessionStatus status) {
            //Do Product search
            return modelAndView;
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView searchCustomers(@ModelAttribute("customerSearch") CustomerSearchCriteria customerSearchCriteria,
            BindingResult result, SessionStatus status) {
            //Do Customer search
            return modelAndView;
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView printSomething(@ModelAttribute("print") PrintForm printForm,
            BindingResult result, SessionStatus status) {
            //Print something
            return modelAndView;
    }
  }

Above certainly doesn't work as I assumed it would. I get exception saying 'Request method 'POST' not supported'. If I have only one POST method inside above controller say searchProducts it works well. But it won't with more than one methods with POST. I also tried adding hidden parameter in JSP and changing method signatures similar to below only to get the same exception again.

  @RequestMapping(
Edit
Report

2 Answers

12

Your mappings are not completely correct @TMan:

  1. The mappings in web.xml are to get Spring Dispatcher servlet to handle your request - eg. like in your case:

    <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/META-INF/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    

    appServlet *.do So now any request to URI's ending with .do will be handled by Spring's DispatcherServlet

  2. The controller can have a mapping, like in your case:

    @Controller @RequestMapping(value="/search.do")

But where you have gone wrong is in the RequestMapping for the controller :

@Controller
@RequestMapping(value="/search")

The .do at the end of RequestMapping should not be there, as it is purely for the Dispatcher servlet to be invoked, once that is invoked it will handle dispatching to the correct Controller method, so your call to /search.do will end up with the controller.

  1. Now, each method can be annotated with RequestMapping like in your case, with a RequestMethod atribute of RequestMapping, specifying whether to dispatch to the method in case of POST or GET:

    @RequestMapping(method = RequestMethod.GET)
    @RequestMapping(method = RequestMethod.POST)
    

So when there is a POST to the /search.do URI the appropriate method will be called.

In your case, there are multiple methods annotated with the RequestMethod.POST attribute, so the AnnotationMethodHandlerAdapter component of Spring simply doesn't know which method to dispatch to.

There are a couple of things that yo

answered 2011-01-31T13:50:54.910
5

I've had the same problem: two forms (register and contact) on the same page with two submit buttons. Each form has its own validation by Spring.

I've managed to do this in one Controller:

@RequestMapping(value = "/contactOrRegister.do", method = RequestMethod.GET)
public void contactOrRegisterFormGet(@ModelAttribute("contactForm") ContactForm contactForm, @ModelAttribute("registerForm") RegisterForm registerForm) {
    //-----prepare forms for displaying here----
}

@RequestMapping(value = "/contact.do", method = RequestMethod.POST)
public String contactFormPost(@ModelAttribute("contactForm") ContactForm contactForm, BindingResult result, final Model model) {        
    contactValidator.validate(contactForm, result);
    if (result.hasErrors()) {
        model.addAttribute("registerForm", new RegisterForm());
        return "contactOrRegister";
    }
    //--- validation is passed, do submit for contact form here ---
}

@RequestMapping(value = "/register.do", method = RequestMethod.POST)
public String registerFormPost(@ModelAttribute("registerForm") RegisterForm registerForm, BindingResult result, final Model model) {        
    registerValidator.validate(registerForm, result);
    if (result.hasErrors()) {
        model.addAttribute("contactForm", new ContactForm());
        return "contactOrRegister";
    }
    //--- validation is passed, do submit for register form here ---
}

I need to create a new form (contact or register) and put it in model when validation is failed because "contactOrRegister" view needs both forms to display. So when "contact" form was submitted and has errors the "register" form content will be erased. This way fits for me.

The contactOrRegister.jsp contains both forms with different action:

 <form:form action="/register.do" modelAttribute="registerForm" method="POST">
    <!-- register form here -->
 </form:form>

 <form:form action="/contact.do" 
answered 2011-08-18T09:11:47.997

Your Answer