2012-04-04 16 views
5

freemarkerを使用して、最新のspring mvc。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つのモデルのプロパティがいくつかあります。

    検証occurrs前
  2. 、私は手動で2つのモデルを作成する必要があり、フォームからの値を設定し、手動でも、いくつかのプロパティを設定します。

  3. コールは、両方のモデル(MODEL1、MODEL2)に検証、および追加しますこれらのエラーメッセージは、エラーが発生した場合、同じビューページに戻す必要があります。

  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:フォームBean

これには二つの方法があります。

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

より正確な方法は、私が唯一Model1Model2しかしから必要とフィールドを借りるように、実際にMyModelを定義することです:単純なアプローチは、(私はあなたがすでにやったと推定した)フォームBeanを定義することですこれがあなたのやり方に合っているかどうかはわかりません。

ステップ2:

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

ステップ3:検証

データ

春バインディングは、あなたのビューで、このようなform構造を持っている場合は、あなたのためにこれを行います

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 />を使ってバネをバリデータに登録させていると推測します。それ以外の場合は、それらを構成する必要があります。

ステップ4:カスタムモデル処理要求処理前

あなたのオリジナルのアイデアは、この仕事のためにいくつかのデータバインダーを使用することです。あなたの説明では、このデータ処理がフォームデータからのデータに依存していないことにも言及しています。

デザインとモジュール性に関しては、データバインダーはそのような目的には適していないと私は信じています。第二に、フォームへのデータ依存がないため、主な理由はデータバインディングエラー処理を可能にすることです。

私の提案は、今あなたがpublic ModelAndView myMethod(@Valid MyModel model, BindingResult bindingResult)にいるとしましょうということです。おそらく、あなたはここで他のサービス豆にアクセスすることができます。したがって、いくつかのサービスBeanに、refineまたはprepare(ちょうど名前)のmodelというメソッドを持つことができます。 例外またはあなたに合ったその他のメカニズムに基づいて、bindingResultを使用してエラーを再度返すことができます。

さらにDI/IoCの方法をご希望の場合は、Spring interceptorsを利用することもできます。しかし、このようにして、MyModelを傍受してModelAndViewから抽出して処理する必要があります。

こちらがお役に立てば幸いです。

0

Hibernate Validator 4.2は、メソッドレベルの検証をサポートしています。メソッド内で2つのモデルを渡すコードを少しリファクタリングして検証することができます。

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

あなたはそれが私たちができないデータであるとして、それは通常、ユーザー入力を検証するために、最も理にかなっているように、これは、珍しい問題である。この

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

     //continue ... 
} 
0

のようなものを持つことができますコントロール。あなたが既にそれを知っていたと確信しているからです。

1つのオプションは、モデル入力オブジェクトがユーザー入力、データベースから読み込まれた後で検証するために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"; 
} 

あなたは春BindingResultやエラーのコレクションにバインドすることもできます。私は、次のコードをテストしていない、とBindingResultで直接作業は非常に快適ではないですので、微調整が必​​要になりますしている:

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

あなたはちょうどそのSet<ConstraintViolation>を使用して、JSPのエラーを吐き出すしようとしている場合あなたのニーズに十分に働く可能性があります

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

あなたは春の<form:errors>タグを使用しようとしている場合は、バインディングの結果を使用する必要があります。

HTH!これ以上質問があれば教えてください。あるいは、この回答でマークを完全に忘れた場合、私は明確にしようとします。

関連する問題