2012-04-04 26 views
5

最新春季mvc,使用freemarker。如何驗證spring mvc表單的困惑,我有什麼選擇?

希望有人可以告訴我什麼我的選項是用spring mvc驗證一個表單,以及推薦的方法是做什麼。

我有一個不直接映射到模型的表單,它有輸入字段,當發佈時,將用於初始化2個模型對象,然後我需要驗證,如果他們通過,我將保存它們。

如果它們失敗了,我想返回到表單,用用戶輸入的內容預填充值並顯示錯誤消息。

我已經讀到這裏,有大約2種方法,一旦其中我已經做了,並瞭解它是如何工作的:

@RequestMapping(...., method = RequestMethod.POST) 
public ModelAndView myMethod(@Valid MyModel, BindingResult bindingResult) { 
    ModelAndView mav = new ModelAndView("some/view"); 
    mav.addObject("mymodel", myModel); 

    if(bindingResult.hasErrors()) { 
    return mav; 
    } 

} 

現在這個工作,如果我的形式直接映射到形式,但在我的情況我有:

  1. 表格字段不映射到任何特定的模型,他們有一些來自2個模型的屬性。

  2. 驗證occurrs之前,我需要手動創建的2種型號,從表格中設置的值,然後手動設置一些屬性也:在兩種模型(模型1,模型2)

  3. 呼叫驗證,並追加這些錯誤消息給我需要傳遞迴相同視圖頁面的錯誤集合,如果事情不起作用的話。

  4. 當表單的帖子,我必須做一些數據庫調用,以及基於這些結果可能需要添加額外的信息到錯誤集合。

有人能告訴我如何做這種驗證?

僞代碼如下:

Model1 model1 = new Model1(); 
    Model2 model2 = new Model2(); 

    // manually or somehow automatically set the posted form values to model1 and model2. 

    // set some fields manually, not from posted form 
    model1.setProperty10(GlobalSettings.getDefaultProperty10()); 
    model2.setProperty11(GlobalSettings.getDefaultProperty11()); 

    // db calls, if they fail, add to errors collection 

    if(bindingResult.hasErrors()) { 
    return mav; 
    } 

    // validation passed, save 
    Model1Service.save(model1); 
    Model2Service.save(model2); 

    redirect to another view 

更新

我一直在使用我的模型JSR 303註解,現在,這將巨大的,如果我可以使用那些依然。

更新II

請閱讀下面的賞金爲說明什麼,我正在尋找一個總結。

回答

8

基於類似的經歷,我想提出以下建議,並就在身邊我對要採取的方法的最後一步的註釋。我使用你編號的步驟列表。

步驟1:Form Bean的

這有兩種方式。簡單的方法是定義一個表單bean(即我相信你已經做了):

class MyModel { 
    private Model1 model1; 
    private Model2 model2; 
    // standard Java bean stuff 
} 

更精確的方法是實際定義MyModel這樣的,我只是借用,從Model1Model2但需要領域我不確定這是否適合你的方式。

第2步:數據綁定

春季做到這一點你,如果你有這樣的form結構視圖:

<form:form modelAttribute="myModel"> 
    <form:input path="model1.somePropertyToBeSet" /> 
</form:form> 

第3步:驗證

使用Spring custom validations,您可以定義cust OM約束:

自定義約束
@interface Model1Constraint {} 
@interface Model2Constraint {} 

class MyModel1 { 

    @Model1Constraint 
    private Model1 model1; 

    @Model2Constraint 
    private Model2 model2; 

    // ... 

} 

然後註冊您的自定義驗證:

class Model1ConstraintValidator implements ConstraintValidator<Model1Constraint, Model1> { 
// implementation of isValid and initalize 
} 

與同爲Model2Constraint。使用自定義驗證器,您可以檢查在將MyModel傳遞到請求處理方法之前需要確保哪些邏輯。我還假定你已經使用<mvc:annotation-driven />讓Spring註冊驗證器;否則,你應該配置它們。

第4步:自定義模式處理請求的處理之前

你最初的想法是使用一些數據綁定這項工作。在你的描述中,你也提到這個數據處理不是取決於來自表單數據的數據。

關於設計和模塊化,我不認爲數據綁定器是這樣一個目的的好地方。其次,由於表單沒有數據依賴性,所以主要原因是允許數據綁定錯誤處理。

所以,我的建議是,讓我們說,現在你在public ModelAndView myMethod(@Valid MyModel model, BindingResult bindingResult)。據推測,你可以在這裏訪問其他服務bean。因此,您可以在某個服務bean中使用一個方法,該服務bean可以在此處填入refineprepare(只是名稱)model。根據例外情況或適合您的任何其他機制,您可以使用bindingResult再次返回錯誤。

作爲另一個建議,如果您希望採用更多的DI/IoC方法,您還可以利用Spring interceptors。但是這樣,你應該從ModelAndView中提取MyModel進行截取並繼續。

我希望這會有所幫助。

0

Hibernate Validator 4.2支持方法級別驗證。您可以稍微重構代碼以傳遞方法中的兩個模型,並驗證它們。

http://java.dzone.com/articles/method-validation-spring-31

,你可以有這樣的事情

public void persistUser(@NotNull @Valid Model1 model1, @NotNull @Valid Model2 model2) { 

     //continue ... 
} 
0

這是一個不尋常的問題,因爲它通常是很有道理的,以驗證用戶的輸入,因爲這是數據,我們不能控制。這就是說,因爲我確信你已經知道......

一個選擇是直接使用JSR 303驗證api驗證你的模型對象,它們已經從用戶輸入,數據庫等。

下面是一個例子:

@RequestMapping(value=...) 
public String myMethod(MyForm form, Model m) { 

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
    Validator validator = factory.getValidator(); 

    Model1 model1 = createModel1FromUserInput(form); 
    Model2 model2 = createModel2FromUserInput(form); 

    Set<ConstraintViolation<?>> modelViolations = validator.validate(model1); 
    modelViolations.add(validator.validate(model2)); 
    if(modelViolations.size() != 0) { 
     m.addAttribute("violations", modelViolations); 
     m.addAttribute("form", myForm); // add the form back to the model so it is populated 
     return "formPage"; 
    } 
    return "successPage"; 
} 

您可能偏向於結合Spring的BindingResult或錯誤的集合。我沒有測試過下面的代碼,而不是很舒服直接與BindingResult工作,所以它需要的調整:

BindingResult result = ... // not sure about the constructor 
for(ConstraintViolation<?> violation : modelViolations) { 
     result.addError(new ObjectError(violation.getPropertyPath().toString(),violation.getMessage())); 
} 

如果你只是想吐在JSP中的錯誤,然後用Set<ConstraintViolation>可能工作不夠好,你的需求:

<c:forEach items="${violations}" var="violation"> 
    ${violation.propertyPath}: ${violation.message} <br/> 
</c:forEach> 

如果你想使用Spring的<form:errors>標籤,你需要使用綁定的結果。

HTH!如果您還有其他問題,請告訴我。或者如果我完全錯過了這個答案的標記,我會盡力澄清。