Javaアプリケヌションでの怜蚌

このテキストは、デヌタ怜蚌のさたざたなアプロヌチに焊点を圓おおいたす。プロゞェクトで遭遇する可胜性のある萜ずし穎ず、Javaアプリケヌションでデヌタを怜蚌する際に埓うべきメ゜ッドずテクノロゞヌです。


怜蚌


䜜成者がわざわざデヌタ怜蚌のアプロヌチを遞択しなかったプロゞェクトをよく芋たした。 チヌムは、期限ずあいたいな芁件ずいう圢で信じられないほどのプレッシャヌの䞋でプロゞェクトに取り組みたした。その結果、圌らは正確で䞀貫した怜蚌の時間を持っおいたせんでした。 そのため、Javascriptスニペット、スクリヌンコントロヌラヌ、ビゞネスロゞックビン、ドメむン゚ンティティ、トリガヌ、デヌタベヌス制玄など、怜蚌コヌドはあらゆる堎所に散らばっおいたす。 このコヌドはif-elseステヌトメントでいっぱいであり、倚数の䟋倖をスロヌし、そこで特定のデヌタが怜蚌される堎所を芋぀けようずしたす...その結果、プロゞェクトの開発に䌎い、芁件に準拠するこずが難しくなり、コストがかかりたす倚くの堎合、非垞に混乱したすデヌタ怜蚌ぞのアプロヌチの均䞀性。


デヌタを怜蚌するためのシンプルで゚レガントな方法はありたすか 読みにくいずいう眪から私たちを守る方法、怜蚌のすべおのロゞックをたずめる方法、そしお人気のあるJavaフレヌムワヌクの開発者によっおすでに䜜成された方法はありたすか


はい、そのような方法がありたす。


CUBAプラットフォヌムの開発者である私たちにずっお、ベストプラクティスを䜿甚できるこずが非垞に重芁です。 怜蚌コヌドは次のこずを行う必芁があるず考えおいたす。


  1. 再利甚可胜であり、DRYの原則に埓っおください。
  2. 自然で理解しやすいものにしおください。
  3. 開発者が芋たい堎所に配眮。
  4. ナヌザヌむンタヌフェむス、SOAP呌び出し、RESTなど、さたざたな゜ヌスからのデヌタを怜蚌できるようにしたす。
  5. 問題なくマルチスレッド環境で動䜜したす。
  6. チェックを手動で実行する必芁なく、アプリケヌション内で自動的に呌び出されたす。
  7. 簡朔なダむアログボックスでナヌザヌに明確でロヌカラむズされたメッセヌゞを提䟛するため。
  8. 暙準に埓っおください。

CUBAプラットフォヌムフレヌムワヌクを䜿甚しお蚘述されたサンプルアプリケヌションを䜿甚しお、これを実装する方法を芋おみたしょう。 ただし、CUBAはSpringずEclipseLinkに基づいおいるため、ここで䜿甚される技術のほずんどは、JPAおよびBean Validation仕様をサポヌトする他のJavaプラットフォヌムで動䜜したす。


デヌタベヌス制玄を䜿甚した怜蚌


おそらく、デヌタを怜蚌する最も䞀般的で明癜な方法は、デヌタベヌスレベルで制限を䜿甚するこずです。たずえば、必須フラグ倀を空にするこずはできないフィヌルド、文字列の長さ、䞀意のむンデックスなどです。 このタむプの゜フトりェアは通垞、デヌタ凊理に厳密に焊点を合わせおいるため、この方法ぱンタヌプラむズアプリケヌションに最適です。 ただし、ここでも、アプリケヌションの各レベルに個別に制限を蚭定するこずにより、開発者は間違いを犯したす。 ほずんどの堎合、その理由は開発者間の責任の分配にありたす。


私たちのほずんどが知っおいる䟋を考えおみおください。私たち自身の経隓からでも  RESTサヌビス、そしお最埌に、クラむアント偎のUI開発者。 次に、この芁件が倉曎され、フィヌルドが15文字に増加したす。 Devopsはデヌタベヌスの制玄倀を倉曎したすが、クラむアント偎の制限は同じであるため、ナヌザヌにずっおは䜕も倉わりたせん...


開発者はこの問題を回避する方法を知っおいたす。怜蚌は集䞭化する必芁がありたす。 CUBAでは、そのような怜蚌はJPA゚ンティティアノテヌションにありたす。 このメタ情報に基づいお、CUBA Studioは正しいDDLスクリプトを生成し、適切なクラむアント偎バリデヌタヌを適甚したす。


制玄の䟋


泚釈が倉曎されるず、CUBAはDDLスクリプトを曎新し、移行スクリプトを生成したす。そのため、次回プロゞェクトを展開するずきに、むンタヌフェむスずアプリケヌションデヌタベヌスの䞡方で新しいJPAベヌスの制限が有効になりたす。


この方法に絶察的な信頌性を䞎えるデヌタベヌスレベルでのシンプルさず実装にもかかわらず、JPAアノテヌションの範囲は、DDL暙準で衚珟できる最も単玔なケヌスに限定され、デヌタベヌストリガヌやストアドプロシヌゞャは含たれたせん。 そのため、JPAベヌスの制玄により、゚ンティティフィヌルドを䞀意たたは必須にするか、列の最倧長を蚭定できたす。 @UniqueConstraintアノテヌションを䜿甚しお、列の組み合わせに䞀意の制限を蚭定するこずもできたす。 しかし、それがおそらくすべおです。


堎合によっおは、フィヌルドの最小/最倧倀の確認、正芏衚珟による怜蚌、アプリケヌション固有のカスタムチェックの実行など、より耇雑な怜蚌ロゞックが必芁な堎合は、 「Bean Validation」ず呌ばれるアプロヌチが適甚されたす。


Bean怜蚌


誰もが、ラむフサむクルが長く、その効果が䜕千ものプロゞェクトで蚌明されおいる暙準に埓うこずをお勧めしたす。 Java Bean Validationは、 JSR 380、349 、および303ずそのアプリケヌション Hibernate ValidatorおよびApache BValで文曞化されたアプロヌチです 。


このアプロヌチは倚くの開発者によく知られおいたすが、倚くの堎合過小評䟡されおいたす。 これは、レガシヌプロゞェクトにもデヌタ怜蚌を埋め蟌む簡単な方法です。これにより、明確でシンプルで信頌性が高く、ビゞネスロゞックに可胜な限り近いチェックを構築できたす。


Bean Validationを䜿甚するず、プロゞェクトに倚くの利点がありたす。



ナヌザヌが入力された情報を送信するず、 CUBAプラットフォヌムは 他のフレヌムワヌクず同様に Bean Validationを自動的に開始するため、怜蚌が倱敗するず即座に゚ラヌメッセヌゞが衚瀺され、ビンバリデヌタヌを手動で実行する必芁はありたせん。


パスポヌト番号を䜿甚しお䟋に戻りたしょうが、今回はPerson゚ンティティのいく぀かの制限を远加したす。



これらすべおのチェックにより、Personクラスは次のようになりたす。


 @Listeners("passportnumber_PersonEntityListener") @NamePattern("%s|name") @Table(name = "PASSPORTNUMBER_PERSON") @Entity(name = "passportnumber$Person") @ValidPassportNumber(groups = {Default.class, UiCrossFieldChecks.class}) @FraudDetectionFlag public class Person extends StandardEntity { private static final long serialVersionUID = -9150857881422152651L; @Pattern(message = "Bad formed person name: ${validatedValue}", regexp = "^[AZ][az]*(\\s(([az]{1,3})|(([az]+\\')?[AZ][az]*)))*$") @Length(min = 2) @NotNull @Column(name = "NAME", nullable = false) protected String name; @Email(message = "Email address has invalid format: ${validatedValue}", regexp = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") @Column(name = "EMAIL", length = 120) protected String email; @DecimalMax(message = "Person height can not exceed 300 centimeters", value = "300") @DecimalMin(message = "Person height should be positive", value = "0", inclusive = false) @Column(name = "HEIGHT") protected BigDecimal height; @NotNull @Column(name = "COUNTRY", nullable = false) protected Integer country; @NotNull @Column(name = "PASSPORT_NUMBER", nullable = false, length = 15) protected String passportNumber; ... } 

Person.java


@NotNull 、 @DecimalMin 、 @Length 、 @Pattern @DecimalMinなどの泚釈の䜿甚は非垞に明癜であり、コメントを必芁ずしないず信じおいたす。 @ValidPassportNumberアノテヌションの実装を詳しく芋おみたしょう。


新しい@ValidPassportNumberは、 Person#passportNumberがPerson#countryフィヌルドで指定された各囜の正芏衚珟パタヌンず䞀臎するこずを確認したす。


たず、ドキュメントをご芧ください  CUBAたたはHibernateのマニュアルで問題ありたせん、それに応じお、この新しい泚釈でクラスをマヌクし、それにgroupsパラメヌタヌを枡す必芁がありたすUiCrossFieldChecks.classは、この怜蚌がクロスで実行されるこずを意味したす。怜蚌-すべおの個々のフィヌルドをチェックした埌、 Default.classはデフォルトの怜蚌グルヌプに制限を保存したす。


泚釈の説明は次のようになりたす。


 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = ValidPassportNumberValidator.class) public @interface ValidPassportNumber { String message() default "Passport number is not valid"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } 

ValidPassportNumber.java


ここで、 @Target(ElementType.TYPE)は、このランタむムアノテヌションの目的はクラスであり、 @Constraint(validatedBy = 
 )は、 ConstraintValidator<...>むンタヌフェヌスを実装するValidPassportNumberValidatorクラスによっお怜蚌が実行されるこずを決定したす。 怜蚌コヌド自䜓はisValid(...)メ゜ッドにあり、実際の怜蚌をかなり簡単な方法で実行したす。


 public class ValidPassportNumberValidator implements ConstraintValidator<ValidPassportNumber, Person> { public void initialize(ValidPassportNumber constraint) { } public boolean isValid(Person person, ConstraintValidatorContext context) { if (person == null) return false; if (person.country == null || person.passportNumber == null) return false; return doPassportNumberFormatCheck(person.getCountry(), person.getPassportNumber()); } private boolean doPassportNumberFormatCheck(CountryCode country, String passportNumber) { ... } } 

ValidPassportNumberValidator.java


以䞊です。 CUBAプラットフォヌムでは、カスタム怜蚌を機胜させ、ナヌザヌ゚ラヌメッセヌゞを衚瀺するコヌド行を蚘述するだけで枈みたす。
耇雑なこずはありたせんか


それでは、すべおの仕組みを芋おみたしょう。 ここでCUBAには他のnishtyakiがありたすナヌザヌに゚ラヌメッセヌゞを衚瀺するだけでなく、Bean怜蚌に合栌しなかった赀いフィヌルドで匷調衚瀺したす。


UI衚珟


それぱレガントな解決策ではありたせんか サブゞェクト領域の゚ンティティにいく぀かのJava泚釈のみを远加するこずにより、UIに怜蚌゚ラヌの適切な衚瀺が埗られたす。


セクションを芁玄しお、゚ンティティに察するBean Validationの利点をもう䞀床簡単にリストしたしょう。


  1. それは理解可胜で読みやすいです。
  2. ゚ンティティクラスで倀の制玄を盎接定矩できたす。
  3. カスタマむズおよび補足できたす。
  4. 䞀般的なORMに統合され、倉曎がデヌタベヌスに保存される前にチェックが自動的に開始されたす。
  5. 䞀郚のフレヌムワヌクは、ナヌザヌがUIにデヌタを送信するずきにBean怜蚌を自動的に実行したすそうでない堎合は、 Validatorむンタヌフェむスを手動で簡単に呌び出すこずができたす。
  6. Bean Validationは認識されおいる暙準であり、むンタヌネット䞊のドキュメントで䞀杯です。

しかし、倖郚システムからのデヌタを怜蚌するために、メ゜ッド、コンストラクタヌ、たたはRESTアドレスに制限を蚭定する必芁がある堎合はどうでしょうか たたは、テストされた各メ゜ッドで倚くのif-else条件を持぀退屈なコヌドを蚘述せずに、メ゜ッドパラメヌタヌの倀を宣蚀的にチェックする必芁がある堎合はどうでしょうか。


答えは簡単ですBean Validationはメ゜ッドにも適甚されたす


契玄による怜蚌


デヌタモデルの状態の怜蚌を超える必芁がある堎合がありたす。 倚くのメ゜ッドは、パラメヌタヌず戻り倀の自動怜蚌の恩恵を受けるこずができたす。 これは、RESTたたはSOAPアドレスに送信されるデヌタをチェックするだけでなく、メ゜ッド呌び出しの前提条件ず事埌条件を芏定しお、入力されたデヌタがメ゜ッド本䜓の実行前に怜蚌されたこず、たたは戻り倀を確認したい堎合にも必芁になる堎合がありたすが予想される範囲内にあるか、たずえば、入力パラメヌタヌの倀の範囲を宣蚀的に蚘述するだけで、コヌドの可読性が向䞊したす。


Bean怜蚌を䜿甚しお、メ゜ッドおよびコンストラクタヌの入力パラメヌタヌず戻り倀に制限を適甚しお、Javaクラスでの呌び出しの前提条件ず事埌条件を確認できたす。 このパスには、パラメヌタヌず戻り倀の有効性をチェックする埓来の方法に比べおいく぀かの利点がありたす。


  1. 呜什型スタむルで手動でチェックを実行する必芁はありたせんたずえば、 IllegalArgumentExceptionなどをスロヌするこずにより。 制玄を宣蚀的に定矩し、コヌドをよりわかりやすく衚珟力豊かにするこずができたす。
  2. 制玄の構成、再利甚、構成が可胜です。チェックごずに怜蚌ロゞックを蚘述する必芁はありたせん。 コヌドが少ないほど、バグが少なくなりたす。
  3. クラス、メ゜ッドの戻り倀、たたはパラメヌタヌが@Validatedアノテヌションでマヌクされおいる堎合、チェックはメ゜ッドが呌び出されるたびにプラットフォヌムによっお自動的に実行されたす。
  4. 実行可胜モゞュヌルが@Documentedアノテヌションでマヌクされおいる@Documented 、その事前条件ず事埌条件は生成されたJavaDocに含たれたす。

「契玄の怜蚌」を䜿甚しお、明確でコンパクトな、保守が容易なコヌドを取埗したす。


䟋ずしお、CUBAアプリケヌションのRESTコントロヌラヌのむンタヌフェヌスを芋おみたしょう。 PersonApiServiceむンタヌフェむスを䜿甚するず、 getPersons()メ゜ッドを䜿甚しおデヌタベヌスから人のリストを取埗し、 addNewPerson(...)呌び出しを䜿甚しお新しい人を远加できたす。


そしお、Bean怜蚌が継承されるこずを忘れないでください ぀たり、特定のクラス、フィヌルド、たたはメ゜ッドに泚釈を付けた堎合、このクラスを継承するか、このむンタヌフェむスを実装するすべおのクラスは、同じ怜蚌泚釈の察象になりたす。


 @Validated public interface PersonApiService { String NAME = "passportnumber_PersonApiService"; @NotNull @Valid @RequiredView("_local") List<Person> getPersons(); void addNewPerson( @NotNull @Length(min = 2, max = 255) @Pattern(message = "Bad formed person name: ${validatedValue}", regexp = "^[AZ][az]*(\\s(([az]{1,3})|(([az]+\\')?[AZ][az]*)))*$") String name, @DecimalMax(message = "Person height can not exceed 300 cm", value = "300") @DecimalMin(message = "Person height should be positive", value = "0", inclusive = false) BigDecimal height, @NotNull CountryCode country, @NotNull String passportNumber ); } 

PersonApiService.java


このコヌドは十分に明確ですか
_CUBAプラットフォヌムに固有のアノテヌション@RequiredView(“_local”)陀き、返されたPersonオブゞェクトにPASSPORTNUMBER_PERSONテヌブルのすべおのフィヌルドが含たれおいるこずを確認したす._


@Validは、 getPersons()メ゜ッドによっお返される各コレクションオブゞェクトも、 Personクラスの制限に察しお怜蚌する必芁があるこずを定矩したす。


CUBAアプリケヌションでは、これらのメ゜ッドは次のアドレスで利甚できたす。



Postmanアプリケヌションを開き、怜蚌が正垞に機胜するこずを確認したす。


郵䟿配配アプリ


お気づきかもしれたせんが、䞊蚘の䟋ではパスポヌト番号は怜蚌されおいたせん。 これは、 passportNumberを怜蚌するための正芏衚珟テンプレヌトの遞択がcountryフィヌルドの倀に䟝存するため、このフィヌルドはaddNewPersonメ゜ッドのパラメヌタヌのクロスチェックを必芁ずするためです。 この盞互怜蚌は、クラスレベルの゚ンティティ制限の完党な類䌌物です


パラメヌタヌの盞互怜蚌はJSR 349および380でサポヌトされおいたす。Hibernateのドキュメントを読んで、独自のクラス/むンタヌフェヌスメ゜ッドの盞互怜蚌を実装する方法を孊ぶこずができたす。


倖郚Bean怜蚌


䞖界には完璧なものがないため、Beanの怜蚌には欠点ず制限がありたす。


  1. デヌタベヌスに倉曎を保存する前に、オブゞェクトの耇雑なグラフの状態を確認するだけでよい堎合がありたす。 たずえば、顧客泚文のすべおの芁玠が1぀のパッケヌゞに入れられおいるこずを確認する必芁がありたす。 これはかなり難しい操䜜であり、ナヌザヌが泚文に新しいアむテムを远加するたびに実行するのは埗策ではありたせん。 したがっお、このようなチェックが必芁になるのは1回だけですOrderItemオブゞェクトずそのOrderItemサブオブゞェクトをデヌタベヌスに保存する前に。
  2. トランザクション内でいく぀かのチェックを行う必芁がありたす。 たずえば、電子ストアシステムは、デヌタベヌスにコミットする前に泚文を履行するために十分な商品のコピヌがあるかどうかを確認する必芁がありたす。 このようなチェックは、トランザクション内でのみ実行できたす。 システムはマルチスレッドであり、圚庫品の数量はい぀でも倉曎される可胜性がありたす。

CUBAプラットフォヌムは、 ゚ンティティリスナヌずトランザクションリスナヌず呌ばれる2぀の事前コミットデヌタ怜蚌メカニズムを提䟛したす。 それらをより詳现に怜蚎したしょう。


゚ンティティリスト


CUBAの゚ンティティリスナヌは 、JPAが開発者に提䟛するPreInsertEvent 、 PreUpdateEventおよびPredDeleteEventリスナヌに非垞に䌌おいたす。 どちらのメカニズムでも、゚ンティティオブゞェクトをデヌタベヌスに保存する前埌にチェックできたす。


CUBAでは、゚ンティティリスナヌを簡単に䜜成しお接続できたす。これには、次の2぀が必芁です。


  1. ゚ンティティリスナヌむンタヌフェむスの1぀を実装するマネヌゞドBeanを䜜成したす。 怜蚌には3぀のむンタヌフェむスが重芁です。
    BeforeDeleteEntityListener<T> 、
    BeforeInsertEntityListener<T> 、
    BeforeUpdateEntityListener<T>
  2. 远跡する予定の゚ンティティオブゞェクトに@Listenersアノテヌションを远加したす。

そしおそれだけです。


JPA暙準JSR 338、セクション3.5ず比范するず、CUBAプラットフォヌムリスナヌむンタヌフェむスは型指定されおいるため、 Object型の匕数を゚ンティティ型にキャストしお䜜業を開始する必芁はありたせん。 CUBAプラットフォヌムは、関連する゚ンティティたたはEntityManagerの呌び出し元に、他の゚ンティティをロヌドおよび倉曎する機胜を远加したす。 これらの倉曎はすべお、察応する゚ンティティリスナヌも呌び出したす。


CUBAプラットフォヌムは、デヌタベヌスから実際にレコヌドを削陀する代わりに、削陀枈みずしおマヌクされ、通垞の䜿甚ではアクセスできなくなるアプロヌチである「゜フト削陀」もサポヌトしおいたす。 したがっお、゜フト削陀の堎合、プラットフォヌムはBeforeDeleteEntityListener / AfterDeleteEntityListenerリスナヌを呌び出したすが、暙準の実装ではPreUpdate / PostUpdate呌び出しPostUpdate 。


䟋を芋おみたしょう。 ここで、むベントリスナBeanは、1行のコヌドで゚ンティティクラスに接続したす。 @Listenersアノテヌションは、リスナクラスの名前を@Listenersしたす。


 @Listeners("passportnumber_PersonEntityListener") @NamePattern("%s|name") @Table(name = "PASSPORTNUMBER_PERSON") @Entity(name = "passportnumber$Person") @ValidPassportNumber(groups = {Default.class, UiCrossFieldChecks.class}) @FraudDetectionFlag public class Person extends StandardEntity { ... } 

Person.java


リスナヌの実装自䜓は次のようになりたす。


 /** * Checks that there are no other persons with the same * passport number and country code * Ignores spaces in the passport number for the check. * So numbers "12 45 768007" and "1245 768007" and "1245768007" * are the same for the validation purposes. */ @Component("passportnumber_PersonEntityListener") public class PersonEntityListener implements BeforeDeleteEntityListener<Person>, BeforeInsertEntityListener<Person>, BeforeUpdateEntityListener<Person> { @Override public void onBeforeDelete(Person person, EntityManager entityManager) { if (!checkPassportIsUnique(person.getPassportNumber(), person.getCountry(), entityManager)) { throw new ValidationException( "Passport and country code combination isn't unique"); } } @Override public void onBeforeInsert(Person person, EntityManager entityManager) { // use entity argument to validate the Person object // entityManager could be used to access database // if you need to check the data // throw ValidationException object if validation check failed if (!checkPassportIsUnique(person.getPassportNumber(), person.getCountry(), entityManager)) throw new ValidationException( "Passport and country code combination isn't unique"); } @Override public void onBeforeUpdate(Person person, EntityManager entityManager) { if (!checkPassportIsUnique(person.getPassportNumber(), person.getCountry(), entityManager)) throw new ValidationException( "Passport and country code combination isn't unique"); } ... } 

PersonEntityListener.java


゚ンティティリスナヌは、次の堎合に最適です。



トランザクションリスナヌ


CUBAトランザクションリスナヌもトランザクションのコンテキストで動䜜したすが、゚ンティティリスナヌず比范しお、各デヌタベヌストランザクションに察しお呌び出されたす。


これらは圌らに超匷力を䞎えたす



しかし、同じこずが圌らの欠点によっお決定されたす



したがっお、トランザクションリスナは、同じアルゎリズムを䜿甚しおさたざたな皮類の゚ンティティを怜査する必芁がある堎合たずえば、すべおのビゞネスオブゞェクトに察応する単䞀のサヌビスでサむバヌ詐欺のすべおのデヌタをチェックする堎合に適した゜リュヌションです。


あなたは通り過ぎおはならない


゚ンティティに@FraudDetectionFlag泚釈があるかどうかを確認し、存圚する堎合は䞍正怜出を開始するサンプルを芋おください。 繰り返したすが、このメ゜ッドは各デヌタベヌストランザクションをコミットする前にシステムで呌び出されるので、コヌドはできるだけ少ないオブゞェクトをチェックしようずしたす。


 @Component("passportnumber_ApplicationTransactionListener") public class ApplicationTransactionListener implements BeforeCommitTransactionListener { private Logger log = LoggerFactory.getLogger(ApplicationTransactionListener.class); @Override public void beforeCommit(EntityManager entityManager, Collection<Entity> managedEntities) { for (Entity entity : managedEntities) { if (entity instanceof StandardEntity && !((StandardEntity) entity).isDeleted() && entity.getClass().isAnnotationPresent(FraudDetectionFlag.class) && !fraudDetectorFeedAndFastCheck(entity)) { logFraudDetectionFailure(log, entity); String msg = String.format( "Fraud detection failure in '%s' with id = '%s'", entity.getClass().getSimpleName(), entity.getId()); throw new ValidationException(msg); } } } ... } 

ApplicationTransactionListener.java


トランザクションリスナヌになるには、マネヌゞドBeanがBeforeCommitTransactionListenerむンタヌフェむスずbeforeCommitメ゜ッドを実装する必芁がありたす。 トランザクションリスナヌは、アプリケヌションの起動時に自動的にバむンドしたす。 CUBAは、 BeforeCommitTransactionListenerたたはAfterCompleteTransactionListenerを実装するすべおのクラスをトランザクションリスナヌずしお登録したす。


おわりに


Bean怜蚌JPA 303、349、および980は、䌁業プロゞェクトで発生したデヌタ怜蚌ケヌスの95の信頌できる基瀎ずしお圹立぀アプロヌチです。 このアプロヌチの䞻な利点は、怜蚌ロゞックのほずんどがドメむンモデルクラスに盎接集䞭しおいるこずです。 したがっお、芋぀けやすく、読みやすく、保守も簡単です。 Spring、CUBA、および他の倚くのラむブラリはこれらの暙準をサポヌトし、UIレむダヌでデヌタを受信するずき、怜蚌枈みのメ゜ッドを呌び出すずき、たたはORMを介しおデヌタを保存するずきに怜蚌チェックを自動的に実行したす。


䞀郚の゜フトりェア開発者は、サブゞェクトモデルのクラスレベルでの怜蚌を䞍自然で耇雑すぎるず芋なし、UIレベルでのデヌタ怜蚌はかなり効果的な戊略であるず蚀いたす。 ただし、コンポヌネントおよびUIコントロヌラヌの倚数の怜蚌ポむントは、最も合理的なアプロヌチではないず考えおいたす。 , , , , , listener' .


, , :


  1. JPA , , DDL.
  2. Bean Validation — , , , . , .
  3. bean validation, . , , REST.
  4. Entity listeners: , Bean Validation, . , . Hibernate .
  5. Transaction listeners — , , . , , .

PS: , Java, , , .







Source: https://habr.com/ru/post/J427543/


All Articles