web-dev-qa-db-ja.com

Spring Web MVC-個々のリクエストパラメーターを検証する

Spring Web MVC 3.0でwebappを実行していますが、そのシグネチャがおおよそ次のようなコントローラーメソッドをいくつか持っています。

@RequestMapping(value = "/{level1}/{level2}/foo", method = RequestMethod.POST)
public ModelAndView createFoo(@PathVariable long level1,
        @PathVariable long level2,
        @RequestParam("foo_name") String fooname,
        @RequestParam(value = "description", required = false) String description);

検証を追加したい。たとえば、descriptionを特定の長さに制限するか、foonameに特定の文字のみを含める必要があります。この検証が失敗した場合、チェックされていない例外をスローするのではなく、ユーザーにメッセージを返します(データをDAOレイヤーに浸透させるとどうなります)。私はJSR303を知っていますが、JSR303を使用したことがなく、SpringコンテキストでJSR303を適用する方法をよく理解していません。

私が理解したことから、別のオプションは@RequestBodyをドメインオブジェクト全体にバインドし、そこに検証制約を追加することですが、現在私のコードは上記のように個々のパラメータを受け入れるように設定されています。

このアプローチを使用して入力パラメーターに検証を適用する最も簡単な方法は何ですか?

48
Dan

それを行うために組み込まれているものは何もありません。とにかく notyet です。現在のリリースバージョンでは、自動検証を行う場合は、WebDataBinderを使用してパラメーターをオブジェクトにバインドする必要があります。 SpringMVCを使用している場合は、このタスクの最初の選択ではない場合でも、学ぶ価値があります。

次のようになります。

public ModelAndView createFoo(@PathVariable long level1,
        @PathVariable long level2,
        @Valid @ModelAttribute() FooWrapper fooWrapper,
        BindingResult errors) {
  if (errors.hasErrors() {
     //handle errors, can just return if using Spring form:error tags.
  }
}

public static class FooWrapper {
  @NotNull
  @Size(max=32)
  private String fooName;
  private String description;
//getset
}

クラスパスにHibernate Validator 4以降があり、デフォルトのディスパッチャセットアップを使用している場合は、「動作するはずです」。

コメントがかなり大きくなったため編集:

メソッドのシグネチャにあるオブジェクトのうち、「予想される」もののいずれでもないオブジェクトは、SpringがHttpRequestModelMapなどの注入方法を知っているため、データバインドされます。これは、単純なケースでは、リクエストパラメータ名をBeanプロパティ名と照合し、セッターを呼び出すだけで実現されます。 @ModelAttributeには個人的なスタイルのものがありますが、この場合は何もしていません。メソッドパラメータの@ValidとのJSR-303統合は、WebDataBinderを介して接続されます。 @RequestBodyを使用している場合は、要求の本文に対してSpringが決定するコンテンツタイプに基づくオブジェクトマーシャラーを使用しています(通常はhttpヘッダーからのみ)。ディスパッチャーサーブレット(AnnotationMethodHandlerAdapter本当に)は使用しません任意のマーシャラーの「検証スイッチを反転する」方法があります。 Webリクエストのコンテンツをメッセージコンバーターに渡すだけで、オブジェクトが返されます。 BindingResultオブジェクトは生成されないため、とにかくエラーを設定する場所はありません。

バリデータをコントローラにインジェクトし、取得したオブジェクトで実行するだけで、BindingResultを生成するリクエストパラメータの@Validとの魔法の統合はありません。

29
Affe

これは現在可能になっているようです(Spring 4.1.2で試しました) https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/を参照してください

上記のページから抽出:

  1. MethodValidationPostProcessorをSpring @Configurationクラスに追加します。

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
    
  2. @Validatedをコントローラークラスに追加する

  3. @RequestParamの直前に@Sizeを使用します

    @RequestMapping("/hi")
    public String sayHi(@Size(max = 10, message = "name should at most 10 characters long") @RequestParam("name") String name) {
        return "Hi " + name;
    

    }

  4. @ExceptionHandlerメソッドでConstraintViolationExceptionを処理する

38
anre

検証する必要のあるリクエストパラメータが複数ある場合(Http[〜#〜] get [〜#〜]または[〜#〜] post [〜#〜])。 カスタムモデルクラスを作成し、@Validを一緒に使用することもできます@ModelAttributeでパラメーターを検証します。この方法で Hibernate Validator または javax.validator api を使用して、パラメーターを検証できます。次のようになります。

リクエスト方法:

@RequestMapping(value="/doSomething", method=RequestMethod.GET)
public Model dosomething(@Valid @ModelAttribute ModelRequest modelRequest, BindingResult result, Model model) {

    if (result.hasErrors()) {
        throw new SomeException("invalid request params");
    }

    //to access the request params
    modelRequest.getFirstParam();
    modelRequest.getSecondParam();

    ...   
}

ModelRequestクラス

class ModelRequest {

    @NotNull
    private String firstParam;

    @Size(min = 1, max = 10, message = "You messed up!")
    private String secondParam;

    //Setters and getters

    public void setFirstParam (String firstParam) {
        this.firstParam = firstParam;
    }

    public String getFirstParam() {
        return firstParam;
    }

    ...
}

お役に立てば幸いです。

17
MasterV