web-dev-qa-db-ja.com

検証はどのレイヤーに配置する必要がありますか?

Spring Bootを使用してRest APIを作成し、Hibernate Validationを使用してリクエスト入力を検証しています。

しかし、他の種類の検証も必要です。たとえば、更新データをチェックする必要がある場合、会社IDが存在しない場合は、カスタム例外をスローします。

この検証は、サービス層またはコントローラー層に配置する必要がありますか?

サービス層:

 public Company update(Company entity) {
    if (entity.getId() == null || repository.findOne(entity.getId()) == null) {
        throw new ResourceNotFoundException("can not update un existence data with id : " 
            + entity.getId());
    }
    return repository.saveAndFlush(entity);
}

コントローラー層:

public HttpEntity<CompanyResource> update(@Valid @RequestBody Company companyRequest) {
    Company company = companyService.getById(companyRequest.getId());
    Precondition.checkDataFound(company, 
        "Can't not find data with id : " + companyRequest.getId());

    // TODO : extract ignore properties to constant

    BeanUtils.copyProperties(companyRequest, company, "createdBy", "createdDate",
            "updatedBy", "updatedDate", "version", "markForDelete");
    Company updatedCompany = companyService.update(company);
    CompanyResource companyResource = companyAssembler.toResource(updatedCompany);
    return new ResponseEntity<CompanyResource>(companyResource, HttpStatus.OK);
}
19
fdarmanto

コントローラー層とサービス層の両方が特定のインターフェースを公開します。インターフェイスは、インターフェイスの使用方法に関する規約を定義します。コントラクトは通常、どの引数(およびそのタイプと値)が予期されるか、どの例外がスローされるか、どの副作用が発生するかなどを意味します。

これで、検証は基本的にコントローラーのupdate()メソッドとサービスレイヤーのupdate()メソッドのコントラクトの適用になります。どちらも非常によく似た契約を結んでいるため、検証(契約の実施)も一般的になるのは当然です。

これを行う1つの可能な方法は、このコントラクトの検証を分離し、両方のレイヤーで呼び出させることです。これは通常、最も明確です。各クラス/メソッドは独自の規約を適用しますが、パフォーマンス(データベースへのアクセス)またはその他の理由により、多くの場合非実用的です。

他の可能性は、サービス層コントラクトで検証が失敗した場合の動作を明示的に定義しながら、この検証をサービス層に委任することです。サービスレイヤーは通常、いくつかの一般的な検証エラー(または例外をスロー)を返し、コントローラーレイヤーはエラーに対して特定の方法で反応する必要があります。

この設計では、サービスレイヤーのビジネスロジック(非常に汎用的である必要があります)とコントローラー(統合ロジックを処理する)の間の結合が多すぎるという危険があります。

とにかく、これはかなり物議を醸す質問であり、100人が100件の回答で答えます。これは私の見解です。

8
qbd

入力はサービス層でチェックする必要があります。

「IDが見つかりません」は論理的なエラー状態です。したがって、コントローラーレイヤーからスローする必要があります。

これも、レイヤー/デザインに依存します。
サービスレイヤーが実行することと、コントローラーレイヤーに期待されること.

1
Paperless

Hibernate検証は、データのintegrityに対するチェックです。 bbddからのRuntimeExceptionを回避するため。それらはConstrainsで制御する必要がある検証とほとんど同じです。ビジネスレイヤーのみフィードである必要があります永続性レイヤーなので、ビジネスレイヤーからのデータの正当性を信頼するかどうかはあなた次第です

DAOには検証を入れません。上位層からの有効なデータを期待しています。エラーが発生した場合は、bbddにその内容を認識する責任を委任します。

次に、ビジネス層での検証が行われます。すべてのビジネス検証は、データのコヒーレンスの維持に焦点を当てており、-その整合性ではありません.

最後に、コントロールレイヤーで以前の検証を行います。そのような層にのみ関連するもの。

どの検証がビジネス層で提供されることが意図されているかがすぐにわかります。最も一般的なのは、IDコントロールです。これは、両方の層で簡単に実装できます。多くのコントローラーまたはクライアントがビジネスレイヤーを消費することが予想される場合は、どこでも同じ検証を繰り返すのではなく、ビジネスレイヤーに配置する優れた候補になります。

コントローラーには、他のファサードでは再現できない独自のルールと条件がある場合があります。次に、そのようなコントローラーに入れる候補です。

何を検証するのか、何に関係なく全員に適用したいのかを考えてください。または、それがコンテキスト検証である場合(「特定のコントロール/ビューファサードでのみ発生する何かを検証しています」。

1
Laiv

Javaショップでは、Webウィジェットの検証を3つの別々の操作に意図的に分割しています。

  1. 基本的なフォーマット-数値は数値でなければなりません。日付は有効な日付である必要があります。通常、この検証は無料で行われます-Webフレームワークがウィジェットのコンテンツをモデルにバインドするときにそれを行います。
  2. 単一のウィジェット検証-日付は過去でなければなりません。整数は1から100の間でなければなりません。 customerIdはデータベースなどに存在する必要があります。これはほとんどの場合コントローラーレイヤーに属しますが、データリポジトリからのサポートが必要になる場合があります。
  3. ウィジェット間の検証-チェックアウト日はチェックイン日より後でなければなりません。死の日付を生年月日の前にすることはできません。これは間違いなくビジネスルールの検証です。これもコントローラーレイヤーに配置する傾向がありますが、ビジネスバリデーターにシフトして再利用できるようにすることもできます。

レイヤー1が失敗した場合、2または3はチェックされません。同様に、1が成功し、2が失敗した場合、3は実行されません。これにより、偽のエラーメッセージが生成されなくなります。

ウィジェットのコンテンツではなく、REST呼び出しの値について質問していますが、同じ原則が適用されます。

0
kiwiron