web-dev-qa-db-ja.com

サービス層から複数のエラーを返す

WebアプリケーションにSpringを使用しています。 Personエンティティの作成などのフォームでユーザーの入力を検証するには、JSR 303検証を使用してnull /空ではない、または有効なパターンなどをチェックします。ただし、フィールドが一意であることを確認するなど、サービスレイヤーでチェックすることもあります。データベースで例外がスローされない場合。この例外をコントローラーでキャッチし、フィールドにエラーを追加します。

これは基本的に、ここでベンJがオプション1で行っていることです https://stackoverflow.com/questions/3224749/passing-errors-back-to-the-view-from-the-service-layer

サービス層

public Person createPerson(String username, String fullName, String specialCode)
        throws DuplicateUsernameException {
    // Check if username exists and throw exception otherwise create person.
    if (checkUsernameExists(username)) {
        throw new DuplicateUsernameException();
    }
    Person person = new Person(username, fullName, specialCode);
    return personDao.create(person);
}

コントローラ

void createPerson(Form form, Errors errors) {

    try {
        service.createPerson(form.getUsername(), form.getFullName(),
                form.getSpecialCode());
    } catch (DuplicateUsernameException e) {
        errors.add("username", "This username exists");
    }

    // render view
    ...
}

これまではこれでうまくいきましたが、2つのフィールドが個別に一意であり、ユーザーに通知したいことを確認する必要があります。上記の例で、specialCodeも一意であることを確認したい場合は、サービスレイヤーの既存のチェックの下に別のチェックを追加して、別のDuplicateSpecialCodeExceptionをスローできます。

サービス層

public Person createPerson(String username, String fullName, String specialCode)
        throws DuplicateUsernameException, DuplicateSpecialCodeException {
    if (checkUsernameExists(username)) {
        throw new DuplicateUsernameException();
    }
    if (checkSpecialCodeExists(specialCode)) {
        throw new DuplicateSpecialCodeException();
    }
    Person person = new Person(username, fullName, specialCode);
    return personDao.create(person);
}

コントローラ

void createPerson(Form form, Errors errors) {

    try {
        service.createPerson(form.getUsername(), form.getFullName(),
                form.getSpecialCode());
    } catch (DuplicateUsernameException e) {
        errors.add("username", "This username exists");
    } catch (DuplicateSpecialCodeException e) {
        errors.add("specialCode", "This special code exists");
    }

    // render view
    ...
}

問題は、ユーザーが重複したユーザー名と重複したSpecialCodeを送信すると、重複したユーザー名のみが通知されることです。両方のフィールドを表示したい。

これを行うきちんとした方法は何ですか?

これまでの私の考えは:

  • すべてのエラーを含む例外をスローします。
  • Errorsオブジェクトをサービスに渡し、これにエラーを追加します。

これらの方法はどちらも、フィールドの名前と適切なエラーコードを知っているサービスレイヤーに依存します。このエラーコードは、レイヤーを別々に保つことに反するようです。

6
Goose

ほとんどの言語では、例外は他のクラスと同じように機能するクラスです。プロパティまたはメソッドをそれらに追加できます。それでは、UnableToCreatePersonException()のコンストラクタでデータ構造または別の種類のエラーDTOまたはエラーDTOのリストを渡すことを許可しないのはなぜですか?例外の一部が実装するIMultipleErrorsExceptionのような、エラーDTOのリストを返すgetAllErrors()などのメソッドを持つインターフェイスを定義することもできます。各エラーDTOには、適切なエラーメッセージを含む翻訳のキーが含まれる場合があり、コントローラーの責任により、これらのメッセージが適切な言語でユーザーに返されるようになります。または、DTOは、サービス層の例外からフィールドやエラーメッセージへのマッピングを処理できる、より洗練されたタイプである可能性があります。

1
RibaldEddie