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的答案也非常有用,也是一个很好的(可能更好的?)替代方案来处理多个表单提交。
答案 0 :(得分:11)
你的映射不完全正确@TMan:
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处理
控制器可以有一个映射,就像你的情况一样:
@Controller @RequestMapping(值= “/ search.do”)
但是你出错的地方是控制器的RequestMapping:
@Controller
@RequestMapping(value="/search")
RequestMapping末尾的.do不应该存在,因为它纯粹是为了调用Dispatcher servlet,一旦被调用它将处理调度到正确的Controller方法,所以你调用/search.do最终会得到控制器。
现在,每个方法都可以使用RequestMapping进行注释,就像你的情况一样,使用RequestMapping的RequestMethod属性,指定在POST或GET的情况下是否调度给方法:
@RequestMapping(method = RequestMethod.GET)
@RequestMapping(method = RequestMethod.POST)
因此,当对/search.do URI进行POST时,将调用适当的方法。
在您的情况下,有多个使用RequestMethod.POST属性注释的方法,因此Spring的AnnotationMethodHandlerAdapter
组件根本不知道要分派到哪个方法。
你可以做几件事:
为每个方法设置一个请求映射,这是@Bozho建议的方式: @RequestMapping(value =“/ customers”method = Request.POST) @RequestMapping(value =“/ products”method = Request.POST) 所以现在你的请求URI将是
/search/customers.do /search/products.do 你应该做POST以获得正确的调度方法。
一起摆脱method = Request.POST并依赖上面的@RequestMapping来找到正确的方法。
你可以将一个可选的params属性传递给RequestMapping,这也是一种帮助Spring找到你正确派遣方法的方法:
@RequestMapping(method = Request.POST,params =“customers”)
在请求中包含客户参数或在请求中说出产品参数。
最简单的是选项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";
时,这非常有用。