Spring 3 MVC使用单个Controller处理多个表单提交

时间:2011-01-31 11:01:44

标签: spring-mvc java-ee controller

Spring 3 MVC使用Controller处理多个表单提交。

我正在开发具有多种形式的JSP页面。 1)搜索客户,2)搜索产品,3)打印东西等。我有一个不同的表单绑定对象绑定到每个表单,我的控制器代码看起来类似于下面

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

以上肯定不会像我想象的那样有效。我得到例外说'请求方法'POST'不支持'。如果我在控制器上面只有一个POST方法,请说searchProducts可以正常工作。但是POST不会有多种方法。我也尝试在JSP中添加隐藏参数并更改类似于下面的方法签名,以便再次获得相同的异常。

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

任何人都可以建议正确的方法来实现上述目标吗?此外,任何对源材料或进一步阅读的参考将不胜感激。感谢。

编辑#1:使用params =“pageAction = searchProduct”的上述方法可以完美地工作,只要您在JSP中获得隐藏参数(请参阅下面的评论)。除此之外,@ Bozho和@Biju Kunjummen的答案也非常有用,也是一个很好的(可能更好的?)替代方案来处理多个表单提交。

4 个答案:

答案 0 :(得分:11)

你的映射不完全正确@TMan:

  1. web.xml中的映射是让Spring Dispatcher servlet处理您的请求 - 例如。就像你的情况一样:

    <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结尾的URI的请求都将由Spring的DispatcherServlet处理

  2. 控制器可以有一个映射,就像你的情况一样:

    @Controller @RequestMapping(值= “/ search.do”)

  3. 但是你出错的地方是控制器的RequestMapping:

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

    RequestMapping末尾的.do不应该存在,因为它纯粹是为了调用Dispatcher servlet,一旦被调用它将处理调度到正确的Controller方法,所以你调用/search.do最终会得到控制器。

    1. 现在,每个方法都可以使用RequestMapping进行注释,就像你的情况一样,使用RequestMapping的RequestMethod属性,指定在POST或GET的情况下是否调度给方法:

      @RequestMapping(method = RequestMethod.GET)
      @RequestMapping(method = RequestMethod.POST)
      
    2. 因此,当对/search.do URI进行POST时,将调用适当的方法。

      在您的情况下,有多个使用RequestMethod.POST属性注释的方法,因此Spring的AnnotationMethodHandlerAdapter组件根本不知道要分派到哪个方法。

      你可以做几件事:

      1. 为每个方法设置一个请求映射,这是@Bozho建议的方式: @RequestMapping(value =“/ customers”method = Request.POST) @RequestMapping(value =“/ products”method = Request.POST) 所以现在你的请求URI将是

        /search/customers.do /search/products.do 你应该做POST以获得正确的调度方法。

      2. 一起摆脱method = Request.POST并依赖上面的@RequestMapping来找到正确的方法。

      3. 你可以将一个可选的params属性传递给RequestMapping,这也是一种帮助Spring找到你正确派遣方法的方法:

        @RequestMapping(method = Request.POST,params =“customers”)

      4. 在请求中包含客户参数或在请求中说出产品参数。

        最简单的是选项1。

        编辑1:添加对好的Spring文档的引用 - http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html

答案 1 :(得分:5)

如果您有多个表单,为什么不将这三个表单映射到不同的URL?

@RequestMapping("/products")
public ModelAndView searchProducts(..)

@RequestMapping("/customers")
public ModelAndView searchCustomers(..)

让您的表单操作指向/search/products/search/customers(不需要.do

答案 2 :(得分:5)

我遇到了同样的问题:两个表单(注册和联系人)在同一页面上有两个提交按钮。 每个表单都有自己的Spring验证。

我设法在一个控制器中执行此操作:

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

我需要创建一个新表单(联系人或注册表)并在验证失败时将其放入模型中,因为“contactOrRegister”视图需要两个表单才能显示。因此,当提交“联系”表单并且有错误时,“注册”表单内容将被删除。这种方式适合我。

contactOrRegister.jsp包含具有不同操作的两种表单:

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

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

答案 3 :(得分:2)

你可以写

  

@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})

在同一控制器上使用多个方法时。当有时用户想要使用GET提交数据或从其他控制器使用return "forward:url";时,这非常有用。