19

Google の Preconditions クラスを使用して、ユーザーの入力データを検証しています。
しかし、Preconditions クラスを使用してユーザーの入力データをチェックする最適なポイントがどこにあるのかが気になります。
まず、以下のようにコントローラーに検証チェックコードを書きました。

@Controller
...
public void register(ProductInfo data) {
    Preconditions.checkArgument(StringUtils.hasText(data.getName()),
        "Empty name parameter.");
    productService.register(data);
}

@Service
...
public void register(ProductInfo data) {
    productDao.register(data);
}

registerしかし、サービスレイヤーのメソッドは、以下のような別のコントローラーメソッドを使用すると 思いました:

@Controller
...
public void register(ProductInfo data) {
    productService.register(data);
}
public void anotherRegister(ProductInfo data) {
    productService.register(data);
}

@Service 
...
public void register(ProductInfo data) {
    Preconditions.checkArgument(StringUtils.hasText(data.getName()),
        "Empty name parameter.");
    productDao.register(data);
}

一方、サービスレイヤーの方法は、1つのコントローラーでのみ使用されます。
私は混乱していました。コントローラーまたはサービスの前提条件を確認するより良い方法はどれですか?
前もって感謝します。

4

4 に答える 4

37

両方の場所で行うのが理想的です。しかし、あなたは2つの異なることを混同しています:

  • 検証 (エラー処理あり)
  • 防御プログラミング (別名アサーション、別名デザイン・バイ・コントラクト)。

コントローラーで検証を行い、サービスで防御プログラミングを行う必要があります。そして、これがその理由です。

適切なエラーをクライアントに送り返すことができるように、フォームと REST リクエストを検証する必要があります。これには、どのフィールドが悪いか、エラーメッセージのローカライズなどが含まれます(現在の例では、ProductInfo.name プロパティが null の場合、スタック トレースを含む恐ろしい 500 エラー メッセージが送信されます)。

Spring には、コントローラー内のオブジェクトを検証するためのソリューションがあります。

適切なエラー メッセージを生成するためにロケールにアクセスできないため、防御的なプログラミングはサービス レイヤーで行われますが、検証は行われません。そうする人もいますが、Spring はあまり役に立ちません。

検証がサービス層で行われないもう 1 つの理由は、ORM が通常 JSR Bean Validation 仕様 (hibernate) を介して既にこれを行っているが、適切なエラー メッセージを生成しないことです。

人々が行う1つの戦略は、RuntimeExceptionguava(およびcommons lang)の代わりにカスタム派生sIllegalArgumentExceptionをスローする独自の前提条件utilsライブラリを作成し、コントローラーでそれらを検証エラーメッセージに変換する例外です。IllegalStateExceptiontrycatch

于 2012-08-20T16:20:35.470 に答える
2

「より良い」方法はありません。サービスが複数のコントローラー (または他のコード) によって使用されると思われる場合は、そこでチェックを行うのが理にかなっています。無効なリクエストがコントローラー内にある間にチェックすることがアプリケーションにとって重要である場合は、そこでチェックを行うのが理にかなっている可能性があります。お気づきのように、これら 2 つは相互に排他的ではありません。両方のシナリオをカバーするには、2 回確認する必要がある場合があります。

別の可能な解決策: Bean Validation (JSR-303) を使用して、チェック (前提条件) を ProductInfo Bean 自体に配置します。そうすれば、チェックを 1 回指定するだけで、必要なものはすべて Bean をすばやく検証できます。

于 2012-08-13T07:32:43.717 に答える
0

前提条件、検証、単純なものかビジネスなものかを問わず、コントローラーまたはサービスレイヤーに到達する前であっても、フィルターレイヤーで処理するかインターセプターで処理する必要があります。

コントローラーレイヤーでチェックすると、要求と応答を委任することを唯一の目的とするコントローラーの単一責任の原則に違反する危険性があります。

サービスレイヤーに前提条件を設定することは、コアビジネスに横断的関心事をもたらしています。

フィルタまたはインセプタは、この目的のために構築されています。フィルタレイヤーまたはインターセプターに前提条件を設定すると、各サーブレットリクエストのスタックに配置できるルールを「選択して一致」させることもできるため、特定のルールを1つのサーブレットリクエストのみに限定したり、重複を導入したりすることはありません。

于 2012-08-16T00:25:57.570 に答える
0

あなたの特別なケースでは、サービス層でそれをチェックし、データの整合性エラーの場合はコントローラーに例外を返す必要があると思います。

@controller
public class MyController{

@ExceptionHandler(MyDataIntegrityExcpetion.class)
public String handleException(MyDataIntegrityExcpetion ex, HttpServletRequest request) {
  //do someting on exception or return some view. 
}

}

また、コントローラーで何をしているかにも依存します。ビューを返すか、@ResponseBody注釈を使用するだけか。Spring MVC には、input/dat 検証用の優れた「すぐに使える」ソリューションがあります。このライブラリを確認することをお勧めします。

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/validation.html

于 2012-08-13T07:33:16.120 に答える