我正在尝试在MultiActionController上应用表单验证(我知道现在已经弃用了控制器类)。
我找到了这个答案(让我更接近目标,但并不完全): How to perform Spring validation in MultiActionController?
好的,所以根据javadoc,异常处理程序方法是控制器的方法,参数为(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception)
。
据我所知(如果我错了,请纠正我),看起来工作流程如下:spring dispatcher-servlet转到控制器的请求方法,如果在其中发生异常执行(例如,由于验证失败导致的绑定异常),它将转到异常处理程序方法,它的异常参数与发生的异常匹配(如果存在这样的异常处理程序方法)。
但与常规控制器的方法不同,此异常处理程序方法没有命令对象参数。 所以我的问题是如何在该方法中访问与请求一起发送的命令对象,其中发生了绑定异常(由于验证错误)?
例如,当我使用注释验证时,我在请求处理程序方法中访问BindingResult和命令对象的(作为方法参数),因此如果出现验证错误,我可以使用命令对象数据加载返回的ModelAndView。
然而,我的异常处理程序方法(在我的MultiActionController中),以
结尾BindException bindException = (BindException) bindingException.getRootCause();
return new ModelAndView("myFormView").addAllObjects(bindException.getModel());
- 提交无效数据后,由于无法找到命令对象,因此无法呈现我的JSP视图(“myFormView”),我得到了异常。
谢谢!
更多信息:
我的控制器(SearchBookController)中的实际请求处理程序方法如下所示:
public ModelAndView list(HttpServletRequest request, HttpServletResponse response, Book book) throws Exception {
ModelMap modelMap = new ModelMap();
//getting a list of books according to the propertiest of the command object book...
modelMap.addAttribute("bookList", bookDAO.listBooks(book));
return new ModelAndView("bookForm", modelMap);
}
我还向控制器添加了以下异常处理程序方法:
public ModelAndView hanldeBindException(HttpServletRequest request, HttpServletResponse response, ServletRequestBindingException bindingException) {
// do what you want right here
//I WOULD LIKE TO ADD HERE THE SUBMITTED BOOK AND THE FETCHED BOOKLIST TO THE ModelAndView, BUT I DO NOT KNOW HOW TO DO IT
BindException bindException = (BindException) bindingException.getRootCause();
return new ModelAndView("bookForm").addAllObjects(bindException.getModel());
}
这是我在servlet-dispatcher.xml中将我的验证器添加到SearchBookController的方法:
<bean name="/book/search.htm" class="com.books.web.SearchBookController" p:validators-ref="searchBookValidator" >
<property name="bookDAO" ref="myBookDAO" />
</bean>
<bean id="searchBookValidator" class="com.books.validator.SearchBookValidator" />
验证器现在只是确保ValidationUtils.rejectIfEmptyOrWhitespace验证书籍属性。
我的视图(bookForm.jsp)显示了提交字段和搜索结果(它在呈现结果视图时重新显示提交的字段)。因此,在提交之后,视图应该同时获得book命令对象和bookList对象。
bookForm.jsp看起来像这样:
<tr>
<td>Details :</td>
<td><form:input path="details" /></td>
<td><form:errors path="details" cssClass="error"/></td>
</tr>
(详情是Book的其中一个字段。)
以下是我尝试加载bookForm.jsp时的异常消息(甚至在提交之前,只是当我尝试加载页面以便填写表单时):
(***当我从servlet-dispatcher.xml中的控制器定义中删除p:validators-ref="searchBookValidator"
时,jsp页面在提交之前和之后正确加载。
HTTP Status 500 -
--------------------------------------------------------------------------------
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/jsp/bookForm.jsp at line 209
206: --%>
207: <tr>
208: <td>Details :</td>
209: <td><form:input path="details" /></td>
210: <td><form:errors path="details" cssClass="error"/></td>
211: </tr>
212: <tr>
Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:510)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:413)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'book' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:174)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:194)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:160)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:147)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:138)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:122)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:408)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:140)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
org.apache.jsp.WEB_002dINF.jsp.bookForm_jsp._jspx_meth_form_005finput_005f0(bookForm_jsp.java:593)
org.apache.jsp.WEB_002dINF.jsp.bookForm_jsp._jspService(bookForm_jsp.java:326)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
更新
按照下面的答案,我现在可以从异常处理程序方法访问命令对象。我仍然有一个问题:如果我提交应该触发错误消息的数据,例如通过
<tr>
<td>Details :</td>
<td><form:input path="details" /></td>
<td><form:errors path="details" cssClass="error"/></td>
</tr>
在结果视图JSP中 - 我没有看到该错误消息。
我的验证器如下所示:
public class SearchBookValidator implements Validator {
//......
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "details", "details.required");
}
}
和我的messages.properties包含以下行:
details.required=details are required
为了帮助我看看会发生什么,我在控制器的hanldeBindException中包含了以下代码:
Map mp = bindException.getModel();
for (Object o : mp.entrySet()) {
Map.Entry pairs = (Map.Entry)o;
System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
当我提交故意错误数据的表单时(即详细信息文本字段为空),我在控制台上收到以下输入:
command = com.books.domain.Book@1173447
org.springframework.validation.BindingResult.command = org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'command' on field 'details': rejected value []; codes [details.required.command.details,details.required.details,details.required.java.lang.String,details.required]; arguments []; default message [null]
你能看出为什么我没有通过<form:errors path="details" cssClass="error"/>
收到任何错误消息吗?
答案 0 :(得分:1)
您的Stacktrace消息
java.lang.IllegalStateException:BindingResult和bean名称'book'的普通目标对象都不可用作请求属性
好吧,我想你有一个Spring表单,如下所示(注意 commandName 属性)
<form:form commandName="book">
但是,在呈现页面时,表单标签会查找名为 book 的任何请求属性。如果Spring确实找到任何名为book的请求属性,您将看到这条好消息
BindingResult和bean名称'book'的普通目标对象都不能作为请求属性
在 list 方法中,我们可以看到您的命令对象未包含在模型中
public ModelAndView list(HttpServletRequest request, HttpServletResponse response, Book book) throws Exception {
/**
* Book object has not been added to the model
*/
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("bookList", bookDAO.listBooks(book);
return new ModelAndView("bookForm", modelMap);
}
改为使用
public ModelAndView list(HttpServletRequest request, HttpServletResponse response, Book book) throws Exception {
return new ModelAndView("bookForm")
.addAttribute("bookList", bookDAO.listBooks(book))
.addAttribute(book);
}
一些注意事项:如果抛出的异常与作为参数的异常匹配,则只会调用您的异常处理程序
// It will be just called when some validation or binding Exception occurs
// Otherwise, Spring will bypass it
public ModelAndView hanldeBindException(HttpServletRequest request, HttpServletResponse response, ServletRequestBindingException bindingException) {
BindException bindException = (BindException) bindingException.getRootCause();
BindingResult bindingResult = (BindingResult) bindException.getModel().get(BindingResult.MODEL_KEY_PREFIX + "book");
/**
* bindingResult.getTarget() returns submitted Book object
*/
return new ModelAndView("bookForm")
.addAllObjects(bindException.getModel())
.addAttribute("bookList", bookDAO.listBooks(bindingResult.getTarget()));
}
<强>更新强>
您是否注册了消息来源?
<!--IT MUST BE CALLED messageSource-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="ValidationMessages"/>
</bean>
以前的设置使用类路径根目录中的ValidationMessages.properties。根据您的属性文件更新
答案 1 :(得分:1)
这已经晚了4年,但希望这会有助于其他人。与rapt的最后一个问题有关,为什么他仍然没有打印<form:errors path="details"/>
。这是因为MultiActionController的默认commandName是&#34;命令&#34; (从他的日志输出中可以看出)
command = com.books.domain.Book@1173447
org.springframework.validation.BindingResult.command = org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'command' on field 'details': rejected value []; codes [details.required.command.details,details.required.details,details.required.java.lang.String,details.required]; arguments []; default message [null]
要获取正确的commandName,请覆盖getCommandName方法以返回所需的commandName(&#34;书&#34;在rapt的情况下),或通过命名约定派生它,如下所示
protected String getCommandName(Object command) {
return Conventions.getVariableName(command);
}
字段的错误&#34;详细信息&#34;现在应该出现了。
答案 2 :(得分:0)
我只是像你一样在Spring MultiActionController中尝试验证。为了从ResourceBundles获取消息我仍然有问题(仍然找不到)但我只是尝试在我的验证器类(验证函数)中设置这样的默认消息:
ValidationUtils.rejectIfEmpty(errors, "fieldName","required.field","this field requred!");
但我仍然无法在我的jsp中看到错误消息然后我尝试在jsp中更改表单commmandName,如下所示:
<form:form action="update.htm" commandName="command">
<!-- Form Field and so on -->
</form:form>
它有效! (还记得在你的控制器中对你的对象名称进行调整)我仍在寻找一种方法来将commandName更改为我们的自定义名称,例如“book”,而不是默认的“command”对象名。
对不起,如果没有帮助。