1。パラメーター検証
開発では、多くの場合、空ではないフィールド、フィールドの長さ制限、メールボックス形式の検証など、フィールド検証のコードを作成する必要があります。個人的には、ビジネスロジックとはほとんど関係のないこれらのコードを書くときに2つのトラブルがあると感じています。
Hibernate Validator(公式文書)は、比較的完全で便利な検証実装方法を提供します。
Spring-Boot-Starter-Webパッケージには、Hibernate-Validatorパッケージがあり、Hibernate Validator依存関係を参照する必要はありません。
2。冬眠検証因子検証デモ
まず、単純なデモを見て、Balidatorの注釈を追加しましょう。
Import org.hibernate.validator.constraints.notblank; import javax.validation.constraints.assertfalse; import javax.validation.constraints.pattern;
@getter@setter@noargsconstructorpublic class demomodel {@notblank(message = "ユーザー名は空になりません")プライベート文字列ユーザー名; @notblank(message = "age nable ve veemy")@pattern(regexp = "^[0-9] {1,2} $"、message = "age scorect")private string age; @assertfalse(message = "false")プライベートブールisfalse; / ***空の場合、チェックされず、空でない場合、チェックされます*/ @pattern(regexp = "^[0-9] {4} - [0-9] {2} - [0-9] {2} $"、メッセージ= "インターフェースの検証、BindingResultは、検証に合格できない結果のコレクションです。
@RequestMapping( "/demo2")public void demo2(@requestbody @valid demomodel demo、bindingResult result){if(result.haserrors()){for(objecteror error:result.getallerrors()){system.out.println(error.getdefaultln(error.efaultmessage(); }}} POSTリクエストで渡されたパラメーター:{"userName":"dd","age":120,"isFalse":true,"birthday":"21010-21-12"}
出力結果:
生年月日は正しくなく、偽でなければなりません
間違った年齢
パラメーター検証は非常に便利です。フィールドでの注釈 +検証が渡されない場合、多くの空ではなくフィールド制限検証コードの手書きを置き換えることができます。以下に、パラメーター検証を再生する方法をより深く理解しています。
3。冬眠検証モード
慎重な読者は、上記の例で、検証に合格しないすべてのセットが一度に返されることを発見したに違いありません。通常、最初のフィールドが検証要件を順番に満たしていない場合、リクエストは直接拒否できます。 Hibernate Validatorには、次の2つの検証モードがあります。
1。通常モード(このモードはデフォルトです)
通常モード(すべての属性がチェックされ、すべての検証障害情報が返されます)
2。モードに戻る速い障害
高速障害リターンモード(検証障害がある限り戻ります)
2つの検証モード構成方法:(公式ドキュメントを参照)
Failfast:True Fast Fail Return Mode False Normal Mode
validatorFactory validatorFactory = validation.byprovider(hibernatevalidator.class).configure().failfast(true).buildvalidatorfactory(); validator validator = validatorfactory.getValidator();
および(hibernate.validator.fail_fast:true fast fail Return Mode False Normal Mode)
validatorFactory validatorFactory = validation.byprovider(hibernatevalidator.class).configure().addproperty( "hibernate.validator.fail_fast"、 "true").buildvalidatorfactory(); validator validator = validatorfactory.getValidator();
4.冬眠の2種類の検証
hibernate validatorを迅速な障害に戻すモードに構成します。
@configurationPublic class validatorconfiguration {@bean public validator validator(){validatorfactory validatorfactory = validation.byprovider(hibernatevalidator.class).configure().addproperty( "hibernate.validator.fail_fast"、 "true").buildvalidatory(); validator validator = validatorfactory.getValidator(); return validator; }}1。パラメーターの検証を要求します
デモの例のように、リクエストパラメーターを確認するときに、@RequestBody Demomodel Demoの間に@Validを追加し、BindIndResultを追加します。複数のパラメーターの場合、次のような複数の@validとBindingResultを追加できます。
public void test()( @requestbody @valid demomodel demo、bindingResult result)public void test()( @requestbody @valid demomodel demo、bindingResult result、 @requestbody @valid demomodel demo2、bindingResult result2)
@RequestMapping( "/demo2")public void demo2(@requestbody @valid demomodel demo、bindingResult result){if(result.haserrors()){for(objecteror error:result.getallerrors()){system.out.println(error.getdefaultln(error.efaultmessage(); }}}2。パラメーター検証を取得します(@RequestParamパラメーター検証)
豆をチェックする方法を使用して、RequestParamの内容を確認する方法はありません。一般に、処理すると、リクエストを取得する(またはパラメーターが少ない)場合、次のコードが使用されます。
@RequestMapping(value = "/demo3"、method = requestmethod.get)public void demo3(@requestparam(name = "grade"、rebyned = true)int grad、@requestparam(name = "classroom"、rebys = true){system.out.println(grade + "、" + classroom); }@validアノテーションを使用して、RequestParamに対応するパラメーターを注釈することは無効です。検証を有効にするには、@validatedアノテーションが必要です。以下に示すように:
a。現時点では、 MethodValidationPostProcessorの豆を使用する必要があります。
@Bean Public MethodValidationPostProcessor MethodValidationPostProcessor(){ / **デフォルトは正常モードであり、すべての検証は情報収集を渡さずに返されます* / return new MethodvalidationPostProcessor(); }または、 MethodValidationPostProcessorのVALIDATORを設定することもできます(この時点で検証に使用されていないため、BALIBATOR構成は機能しません)
@Bean Public MethodValidationPostProcessor MethodValidationPostProcessor(){MethodValidationPostProcessor PostProcessor = new MethodValidationPostProcessor(); / ** validatorモードを高速障害に設定しますreturn*/ postprocessor.setValidator(balidator()); PostProcessorを返します。 } @bean public validator validator(){validatorfactory validatorfactory = validation.byprovider(hibernatevalidator.class).configure().addproperty( "hibernate.validator.fail_fast"、 "true").buildvalidatoryfactory(); validator validator = validatorfactory.getValidator(); return validator; }b。メソッドが配置されているコントローラーに注釈を追加します@validated
@RequestMapping( " /validation")@restcontroller@validatedpublic class validationcontroller { /**いくつかのオブジェクトしかない場合は、コントローラーレイヤーにパラメーターを書き込み、コントローラーレイヤーで確認してください。 */ @RequestMapping(value = "/ demo3"、method = requestmethod.get)public void demo3(@range(min = 1、max = 9、message = "グレードは1-9")@requestparam(name = "grade"、reby = true)int grade、@min(value = 1、message = "class be be be be be clain 99 ")@RequestParam(name =" Classroom "、必須= true)int Classroom){system.out.println(grade +"、 " + classroom); }}c。検証情報プロンプトに戻ります
ご覧のとおりです。検証が失敗した場合、制約型溶解エクセプトの例外がスローされ、同じCatch例外が処理されます。
@ControllerAdvice @componentPublic class GlobalExceptionHandler {@exceptionHandler @ResponseBody @Responsestatus(httpstatus.bad_request)public String handle(validationexception Exception){if(constraintviolationException){constraintviolationException =(ConstraintViolationException); Set <ConstraintViolation <? for(constraintviolation <?> item:違反){ / **確認に失敗した情報を印刷* / system.out.println(item.getMessage()); }} "bad request"を返します。 }}d。検証
ブラウザサービスリクエストアドレス:http:// localhost:8080/validation/demo3?grade = 18&classroom = 888
MethodValidationPostProcessorが高速障害を構成せずに返されたときの出力情報は次のとおりです。
グレードは1〜9のみです
最大クラスは99です
MethodValidationPostProcessorが高速障害リターンで構成されている場合、出力情報は次のとおりです。
グレードは1〜9のみです
ブラウザサービスリクエストアドレス:http:// localhost:8080/validation/demo3?grade = 0&classroom = 0
MethodValidationPostProcessorが高速障害を構成せずに返されたときの出力情報は次のとおりです。
グレードは1〜9のみです
最小クラスは1にすぎません
MethodValidationPostProcessorが高速障害リターンで構成されている場合、出力情報は次のとおりです。
グレードは1〜9のみです
3。モデル検証
検証するモデル:
@datapublic class demo2 {@length(min = 5、max = 17、message = "長さの長さは[5,17]")プライベート文字列長。 / ** @サイズは、文字列、コレクション、マップ、アレイに適した整数を確認できません*/ @size(min = 1、max = 3、message = "size between [1,3]")private string age; @range(min = 150、max = 250、message = "範囲は[150,250]")private int high; @size(min = 3、max = 5、message = "リストのサイズは[3,5]")プライベートリスト<string> list;}モデルを確認すると、次のすべての検証が渡されます。
@Autowired Private Validator Validator; @RequestMapping( "/demo3")public void demo3(){demo2 demo2 = new demo2(); demo2.setage( "111"); demo2.seethigh(150); demo2.setlength( "abcde"); demo2.setlist(new ArrayList <String>(){{add( "111"); add( "222"); add( "333");}}); set <constraintviolation <demo2 >>違反= validator.validate(demo2); for(constraintviolation <demo2> model:violationset){system.out.println(model.getMessage()); }}4。オブジェクトカスケード検証
オブジェクトにはプロパティとして別のオブジェクトが含まれ、@validをプロパティに追加して、オブジェクト内の検証をプロパティとして確認します。(demo2の例を確認する場合、demo2のフィールドを確認できます)
@datapublic class demo2 {@size(min = 3、max = 5、message = "リストのサイズは[3,5]")プライベートリスト<string> list; @notnull @valid private demo3 demo3;} @datapublic class demo3 {@length(min = 5、max = 17、message = "長さは[5,17]")private string extfield;}カスケード検証:
/ ** beanは、高速障害リターンビーンで構成されています*/ @autowired private validator validator; @RequestMapping( "/demo3")public void demo3(){demo2 demo2 = new demo2(); demo2.setlist(new ArrayList <String>(){{add( "111"); add( "222"); add( "333");}}); demo3 demo3 = new Demo3(); demo3.setextfield( "22"); demo2.setdemo3(demo3); set <constraintviolation <demo2 >>違反= validator.validate(demo2); for(constraintviolation <demo2> model:violationset){system.out.println(model.getMessage()); }}DEMO3のextfieldフィールドを確認できます。
5。グループ検証
結論:グループ化シーケンスを検証するときは、指定されたグループ化順序で検証します。以前の検証が失敗した場合、後続のグループ化を検証することはできません。
新しいユーザー情報が追加されたときに、ユーザーIDを検証する必要がない(システムが生成されたため)シナリオがあります。変更するときは、userIDはuserIDを確認する必要があり、ユーザーのグループ検証関数をバリデーターに使用することができます。
バリデーターを通常の検証モード( "hibernate.validator.fail_fast"、 "false")に設定し、検証グループ、グループ、モデルを使用します。
Groupa、GroupB:Public Interface Groupa {} public Interface GroupB {}モデルを確認する:人
@datapublic class person {@notblank @range(min = 1、max = integer.max_value、message = "は0より大きくなければなりません、groups = {groupa.class}) / ** user id* / private integer userid; @notblank @length(min = 4、max = 20、message = "in [4,20]"、groups = {groupb.class}) / ** username* / private string username; @notblank @range(min = 0、max = 100、message = "年齢は[0,100]"、groups = {default.class}) / ** age* / private integer age; @range(min = 0、max = 2、message = "性別は[0,2]"、groups = {groupb.class}) /**性別0:不明。 1:男性; 2:女性*/プライベート整数セックス;}上記のように、3つのグループはそれぞれ次のように検証されています。
a。グループ化
GroupAおよびGroupBタグのグループのみが検証されます。
@RequestMapping( "/demo5")public void demo5(){person p = new person(); / ** GroupA検証は通過しません*/ P.Setuserid(-12); /** Groupa検証パス*///p.setuserid(12); p.setUsername( "a"); P.Setage(110); P.SetSex(5); set <constraintviolation <person >> validate = validator.validate(p、groupa.class、groupb.class); for(constraintviolation <serson> item:validate){system.out.println(item); }}または
@RequestMapping( "/demo6")public void demo6(@validated({groupa.class、groupb.class})人p、bindingResult result){if(result.haserrors()){list.haserror> allerrors = result.getallerrors(); for(objecterrorエラー:allerrors){system.out.println(error); }}}GroupA、GroupB、およびデフォルトが検証されていない場合:
検証情報は次のとおりです。
ConstraintViolationImpl {interpolatedMessage = 'は[4,20]'、propertypath = username、rootbeanclass = class validator.demo.project.model.person = 'である必要があります。 rootbeanclass = class validator.demo.project.model.person、messagetemplate = '} constraintviolationimpl {interpolatedMessage ='性別は[0,2] '、PropertyPath = sex、rootbeanclass = class veridator.demo.project.project.project.project.project.project.project.project.project.project。 [0,2] '}Groupa検証が渡された場合、GroupB、およびデフォルトの検証は渡されません。
検証情報は次のとおりです。
ConstraintViolationImpl {interpolatedMessage = 'は[4,20]'、propertypath = username、rootbeanclass = class validator.demo.project.model.person = 'は[4,20]' '} constraintmessage =' intpolatedMessage = 'genderage =' genderage = 'intpetmessimplである必要があります。 rootbeanclass = class validator.demo.project.model.person、messageTemplate = '性別は[0,2]'}である必要がありますb。グループシーケンス
グループごとに検証するかどうかを指定することに加えて、グループの検証順序を指定することもできます。前のグループの検証が失敗した場合、次のグループの検証は実行されません。
指定されたグループのシーケンス(Groupa》グループbedefaly):
@GroupSequence({Groupa.Class、GroupB.Class、Default.Class})Public Interface GroupOrder {}テストデモ:
@RequestMapping( "/demo7")public void demo7(){person p = new person(); /** GroupA検証は通過しません*///p.setuserid(-12); / ** GroupA検証Pass*/ P.Setuserid(12); p.setUsername( "a"); P.Setage(110); P.SetSex(5); set <constraintviolation <person >> validate = balidator.validate(p、grouporder.class); for(constraintviolation <serson> item:validate){system.out.println(item); }}または
@RequestMapping( "/demo8")public void demo8(@validated({grouporder.class})person p、bindingResult result){if(result.haserrors()){list <objearror> allerrors = result.getAllers(); for(objecterrorエラー:allerrors){system.out.println(error); }}}GroupA、GroupB、およびデフォルトが検証されていない場合:
検証情報は次のとおりです。
constraintViolationImpl {interpolatedMessage = 'は0より大きくなければなりません'、propertyPath = userid、rootbeanclass = class validator.demo.project.model.person、mesagetemplate = 'は0より大きくなければなりません'}Groupa検証が渡された場合、GroupB、およびデフォルトの検証は渡されません。
検証情報は次のとおりです。
ConstraintViolationImpl {interpolatedMessage = 'は[4,20]'、propertypath = username、rootbeanclass = class validator.demo.project.model.person = 'は[4,20]' '} constraintmessage =' intpolatedMessage = 'genderage =' genderage = 'intpetmessimplである必要があります。 rootbeanclass = class validator.demo.project.model.person、messageTemplate = '性別は[0,2]'}である必要があります結論:グループ化シーケンスを検証するときは、指定されたグループ化順序で検証します。以前の検証が失敗した場合、後続のグループ化を検証することはできません。
5。カスタム検証剤
一般的に言えば、カスタム検証は多くの問題を解決できます。しかし、状況を満たすことができない時代もあります。現時点では、Validator Interfaceを実装し、必要なValidatorをカスタマイズできます。
以下に示すように、カスタムケースバリエーターが実装されています。
public enum casemode {upper、lower;}@target({elementtype.method、elementtype.field、elementtype.annotation_type})@retention(retentionpolicy.runtime)@constraint(validatedby = checkcasevalidator.class)@documentededededededpublic@interface checkcase "" "" " class <?> [] groups()default {};クラス<?ペイロード> [] payload()default {}; casemode value();} public class checkcasevalidator constraintvalidator <checkcase、string> {private casemode casemode; public void initialize(checkcase checkcase){this.casemode = checkcase.value(); } public boolean isvalid(string s、constraintvalidatorContext ConstraintValidatorContext){if(s == null){return true; } if(casemode == casemode.upper){return s.equals(s.touppercase()); } else {return s.equals(s.tolowercase()); }}}確認するモデル:
public class demo {@checkcase(value = casemode.lower、message = "username be lowercase")private string username; public string getUsername(){return username; } public void setUsername(string username){this.username = username; }}BALIDATOR構成:
@bean public validator validator(){validatorfactory validatorfactory = validation.byprovider(hibernatevalidator.class).configure().addproperty( "hibernate.validator.fail_fast"、 "true").buildvalidatoryfactory(); validator validator = validatorfactory.getValidator(); return validator; }検証テスト:
@RequestMapping( "/demo4")public void demo4(){demo demo = new demo(); demo.setUsername( "username"); set <constraintviolation <demo >> validate = balidator.validate(demo); for(constraintviolation <demo> dem:validate){system.out.println(dem.getMessage()); }}出力結果:
ユーザー名は小文字である必要があります
6。一般的な注釈
bean validation @nullの組み込み制約注釈付き要素はnull @notnullでなければなりません注釈付き要素はnull @asserttrueでなければなりません @asserttrueはtrueでなければなりません @assertfalse @assertfalse @assertfalseはfalse @min(値)でなければなりません(値)指定された最大値@decimalmin(value)注釈付き要素は数でなければなりません。その値は指定された最小値@decimalmax(値)以上でなければなりません。注釈付き要素は数値でなければなりません。数字であり、その値は許容範囲内でなければなりません @パスト注釈付き要素は過去の日付でなければなりません@length(min =、max =)注釈付き文字列は指定された範囲内でなければなりません@notempty @notemptyは、注釈付きの文字列は非empty @range(min =、max =、message =)でなければなりません。注釈付き要素は0.01を超えている必要があります。 0.01@notnull@decimalmin(value = "0.01"、= trueを含む)private bigdecimal greatorequalthan; @length(min = 1、max = 20、message = "メッセージは空にすることはできません")//
7。参照資料
参考文献:
http://docs.jboss.org/hibernate/validator/4.2/reference/zh-cn/html_single/#validator-gettingstarted