6

freemarkerを使用した最新のSpringMVC。

誰かが春のMVCでフォームを検証するという点で私のオプションが何であるか、そしてこれを行うための推奨される方法を教えてくれることを願っています。

モデルに直接マップしないフォームがあります。入力フィールドがあり、投稿時に2つのモデルオブジェクトを初期化するために使用します。これらのオブジェクトを検証し、合格した場合は保存します。

失敗した場合は、フォームに戻り、ユーザーが入力した値を事前に入力して、エラーメッセージを表示します。

私はあちこちで約2つの方法を読みましたが、そのうちの1つを実行して、それがどのように機能するかを理解しました。

@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. 検証が行われる前に、2つのモデルを手動で作成し、フォームから値を設定し、いくつかのプロパティも手動で設定する必要があります。

  3. 両方のモデル(model1、model2)でvalidateを呼び出し、これらのエラーメッセージをエラーコレクションに追加します。これが機能しない場合は、同じビューページに戻す必要があります。

  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

私が探しているものの要約については、以下の報奨金の説明をお読みください。

4

4 に答える 4

8

同様の経験に基づいて、次のことを提案します。横に、あなたが取りたいアプローチの最後のステップについてコメントがあります。ステップの番号付きリストを使用します。

ステップ 1: フォーム Bean

これには 2 つの方法があります。簡単な方法は、フォーム Bean を定義することです (既に行っていると思います)。

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

より正確な方法は、 andMyModelから必要なフィールドのみを借用するように実際に定義することですが、これがあなたのやり方に合っているかどうかはわかりません。Model1Model2

ステップ 2: データバインディング

formビューにそのような構造がある場合、Spring はこれを行います。

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

ステップ 3: 検証

Spring カスタム検証を使用して、カスタム制約を定義できます。

@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
}

についても同様ですModel2ConstraintMyModelカスタムバリデーターを使用すると、リクエスト処理メソッドに渡される前に確認する必要があるロジックを確認できます。<mvc:annotation-driven />また、Spring にバリデーターを登録させたことがあると思います。それ以外の場合は、それらを構成する必要があります。

ステップ 4: リクエスト処理前のカスタム モデル処理

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

設計とモジュール性に関しては、データ バインダーがそのような目的に適しているとは思えません。次に、フォームにはデータ依存性がないため、データ バインディング エラー処理を許可することが主な理由です。

だから、私の提案は、あなたが今いるとしましょうpublic ModelAndView myMethod(@Valid MyModel model, BindingResult bindingResult)。おそらく、ここで他のサービス Bean にアクセスできます。したがって、この時点で設定したサービス Bean にメソッドを含めることができrefineます。例外または適切なその他のメカニズムに基づいて、 を使用してエラーを再度返すことができます。preparemodelbindingResult

別の提案として、より多くの DI/IoC の方法が必要な場合は、 Spring インターセプターを利用することもできます。しかし、この方法では、インターセプトMyModelから抽出して続行する必要があります。ModelAndView

これが役立つことを願っています。

于 2012-04-08T17:27:05.807 に答える
1

ここに素晴らしい説明があります。Spring MVC 3.0 と JSR 303 の統合 (別名 javax.validation.*) を確認してください。

以下の例も確認してくださいJSR 303 Bean Validation Using Spring 3

于 2012-04-13T12:05:28.747 に答える
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";
}

Spring BindingResult またはエラーのコレクションにバインドすることをお勧めします。私は次のコードをテストしておらず、BindingResult を直接操作することにあまり慣れていないため、微調整が必​​要になります。

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

JSP でエラーを吐き出すだけの場合は、 a を使用するSet<ConstraintViolation>だけで十分に機能する可能性があります。

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

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

チッ!ご不明な点がございましたら、お気軽にお問い合わせください。または、この回答のマークを完全に逃した場合は、明確にしようとします。

于 2012-04-09T15:36:40.230 に答える
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 ...
}   
于 2012-04-09T13:27:29.447 に答える