2011-08-31 68 views
3

我試圖在MultiActionController上應用表單驗證(我知道現在不推薦使用控制器類)。使用MultiActionController進行Spring-MVC表單驗證

我發現這個答案(這讓我更接近我的目標,但不完全): How to perform Spring validation in MultiActionController?

好了,所以根據javadoc,異常處理方法是控制器的方法與參數(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception)

據我所知(糾正我,如果我錯了),它看起來像工作流程如下:春季調度員 - 小服務程序去控制器的請求方法,如果發生異常它的執行(例如,由於驗證失敗而導致的綁定異常),它將轉到異常處理程序方法,使其異常參數與發生的異常相匹配(如果存在這樣的異常處理程序方法)。

但與常規控制器的方法不同,此異常處理程序方法沒有命令對象參數。 所以我的問題是我該如何訪問該方法,與發生綁定異常(由於驗證錯誤)的請求一起發送的命令對象?

例如,當我通過註解使用驗證,我在請求處理程序方法訪問(作爲方法參數)兩者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) 

UPDATE:

按照下面的答案,我現在可以從異常處理程序方法訪問命令對象。但我仍然有一個問題:如果我提交的數據應該引發錯誤信息,例如通過

<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()); 
    } 

當我故意提交表單時g數據(即細節文本字段爲空),我得到的控制檯上輸入如下:

command = [email protected] 
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

您可以發佈呈現頁面的輸出(「無法呈現,因爲無法找到命令對象」) –

+0

謝謝。我剛剛在主標題** MORE INFO **下添加了輸出和更多詳細信息。 – rapt

回答

1

您的堆棧跟蹤信息

java.lang.IllegalStateException:無論BindingResult也不是爲bean名稱「書」可以作爲請求屬性

孔普通的目標對象,我假設你有一個春天的形式如下圖所示(注意命令名屬性)

<form:form commandName="book"> 

然而,當您的頁面已呈現,表單Tag會查找稱爲的書的任何請求屬性。如果春天確實發現任何本書叫請求屬性,你會看到這個漂亮的消息

無論BindingResult也不平原目標對象的bean名字「書」可以作爲請求屬性

在你列表方法,您的命令對象不包括在模型中我們可以看到

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。根據你的屬性文件更新

+0

謝謝。您需要將命令對象添加到從請求處理程序返回的ModelAndView中。我確實將命令對象添加到了ModelAndView,但是在我的代碼中錯誤地忽略了它。**順便說一句**,我還必須將它添加到從異常處理程序返回的ModelAndView,因爲我仍然需要它在視圖中。 BindingResult bindingResult =(BindingResult)bindException.getModel()。get(BindingResult.MODEL_KEY_PREFIX +「command」);'確實讓我能夠訪問命令對象 - 謝謝! – rapt

+0

我想提到後綴應該是「command」,而不是表單的commandName(在我的例子中是「book」)(我剛剛爲null獲得了'bindException.getModel()。get(BindingResult.MODEL_KEY_PREFIX +「book」)' ,所以我沿着Map'bindException.getModel()'進行迭代,並看到命令保存在名稱「command」下)。 **我仍然有一個問題:** JSP中的錯誤標籤不輸出所需的錯誤消息。請在我的主要帖子中看到更多詳細信息** UPDATE ** – rapt

+0

@rapt請參閱UPDATE –

0

我只是想像你做的那樣在Spring MultiActionController中進行驗證。從把ResourceBundle我仍然有問題獲取消息(仍查不到),但我只是嘗試設置這樣的默認郵件在我的驗證類(驗證功能):

ValidationUtils.rejectIfEmpty(errors, "fieldName","required.field","this field requred!"); 

,但我仍然無法在看到錯誤消息我jsp然後我嘗試更改jsp中的表單命令名,如下所示:

<form:form action="update.htm" commandName="command"> 
    <!-- Form Field and so on --> 
</form:form> 

它的工作原理! (還記得你的控制器也要調整你的對象名稱)我仍然在尋找一種方法來將commandName更改爲我們的自定義名稱,比如「book」,而不是默認的「command」對象名稱。

對不起,如果這沒有幫助。

1

這是4年太晚了,但希望這會幫助別人。關於雷普最後一個問題,他爲什麼仍然沒有打印出<form:errors path="details"/>。這是因爲MultiActionController的默認命令名是「命令」(從他的日誌輸出看到的)

command = [email protected] 
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] 

要獲得正確的命令名,覆蓋getCommandName方法返回所需的命令名(在全神貫注的情況下,「書」),或者按照以下命名慣例派生它

protected String getCommandName(Object command) { 
    return Conventions.getVariableName(command); 
} 

現在應出現字段「細節」的錯誤。