Pageコンポーネントのアクション呼び出しの際にリクエストパラメータが正当であるかどうかを検証することができます。この処理を「パラメータチェック」または「バリデーション」と呼びます。Ymirではバリデーションは「制約チェック」の一種です(他の制約チェックの種類としては「権限チェック」があります)。
バリデーションの指定
バリデーションを指定するにはアノテーションを用います。詳細については「制約の指定」を参照して下さい。
処理の詳細
バリデーションはPageコンポーネントへの依存コンポーネントやリクエストパラメータがセットされた後、アクション呼び出しの前に行なわれます。バリデーションに失敗すると、アクションを呼び出す代わりに以下の処理が行なわれます。
- バリデーション失敗に関する詳細情報であるorg.seasar.ymir.message.Notesオブジェクトが「notes」というキーでHttpServletRequestオブジェクトのアトリビュートとしてセットされる。
- Pageコンポーネントが_validationFailedメソッドを持っている場合、それが呼び出される。
- _prerenderメソッドが呼び出される。
_validationFailedメソッドが引数を持つ場合は引数が解決されます。この時Notesオブジェクトがデフォルトの引数値として使用されます。メソッドの引数の解決については「アクションメソッドの引数値の解決」を参照して下さい。
Notesオブジェクト
バリデーションに失敗した場合、その情報がorg.seasar.ymir.message.Notesオブジェクトにセットされます。バリデーションのためのアノテーションが複数指定されている場合は全てのバリデーションが行なわれ、失敗したものについてNotesオブジェクトに情報がセットされます。
Notesオブジェクトは1つまたは複数のorg.seasar.ymir.message.Noteオブジェクトをカテゴリ毎に保持しています。Noteオブジェクトはvalueとパラメータを保持しています。StrutsのActionMessagesとActionMessageと同じようなものと思っていただければいいと思います。
Note#getValue()の値(noteキー)はバリデーションの種類によって異なりますので、これを見ることで失敗したバリデーションが何か知ることができます。
バリデーション失敗に関するNoteオブジェクトは、そのバリデーションの対象であるリクエストパラメータ名と同じ名前のカテゴリに関連付けられてNotesオブジェクトに追加されます。
メッセージの表示
バリデーションエラーメッセージを表示するには、例えば以下のようにします。
まとめて表示する場合、
<ul tal:condition="notes"> <li tal:repeat="note notes/notes" tal:content="note/%value">MESSAGE</li> </ul>
全体に関するメッセージを先頭に表示し、項目ごとのメッセージ項目ごとに表示する場合、
<ul tal:condition="notes/size(org.seasar.ymir.message.GLOBAL_NOTE)"> <li tal:repeat="note notes/org.seasar.ymir.message.GLOBAL_NOTE" tal:content="note/%value">GLOBAL MESSAGE</li> </ul> ... <ul tal:condition="notes/size(param)"> <li tal:repeat="note notes/param" tal:content="note/%value">MESSAGE FOR PARAM</li> </ul>
メッセージを表すNoteオブジェクトがどのように表示されるかについてはNotesオブジェクトを使ったメッセージ文字列の構築を参照して下さい。
メッセージのカスタマイズ
表示されるメッセージをカスタマイズするには、アプリケーションのsrc/main/resourcesにあるmessages.xpropertiesに書かれているプロパティのうち、noteキーと同じキーを持つものを変更して下さい。
xpropertiesファイルの書式は基本的に通常のJavaのプロパティファイルと同じですが、UTF-8で直接非ASCII文字を記述することができます。
国際化対応のアプリケーションの場合は各言語用のmessages_*.xpropertiesを変更して下さい。
バリデーションエラーの対象となったパラメータはそのまま表示されますが、パラメータの表示文字列を変更したい場合はxpropertiesファイルに「label.パラメータ名」というエントリを追加して下さい。例えば「name」というパラメータの表示を「なまえ」にしたい場合はmessages_ja.xproperties(国際化を意識しないアプリケーションの場合はmessages.xpropertiesでも構いません)に以下のようなエントリを追加して下さい:
label.name=なまえ
バリデーションの種類
Ymirが標準で提供しているバリデーションは以下のとおりです。(アノテーションクラスはorg.seasar.ymir.constraint.annotationパッケージ等にあります。)
アノテーション名 | 説明 |
---|---|
Confirmed |
指定されたリクエストパラメータの値が全て一致していることを指定します。 制約の対象となるのは、valueプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 この制約は、例えば確認のためにメールアドレスを2回入力させるようなフォームを処理するために利用することができます。 noteキーはerror.constraint.confirmedです。 指定できるプロパティは以下のとおりです。
|
Datetime |
リクエストパラメータの値が日付パターンにマッチしていることを指定します。 指定されている全てのリクエストパラメータの値が、アノテーションのプロパティとして指定された日付パターンに全体マッチすることを要求します。 制約の対象となるのは、propertyプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 noteキーはerror.constraint.datetimeです。 指定できるプロパティは以下のとおりです。
|
Length |
リクエストパラメータ文字列の長さに関する制約を指定します。 制約の対象となるのは、propertyプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 noteキーはerror.constraint.lengthです。 指定できるプロパティは以下のとおりです。
|
Matched |
リクエストパラメータの値が指定された正規表現パターンにマッチしているという制約を指定します。 制約の対象となるのは、propertyプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 noteキーは、メッセージキー(後述)を指定した場合はerror.constraint.matched.[メッセージキー]です。メッセージキーを指定しなかった場合はerror.constraint.matchedです。 指定できるプロパティは以下のとおりです。
|
Numeric |
リクエストパラメータが数値として解釈可能であるという制約を指定します。 制約の対象となるのは、valueプロパティとpropertyプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 noteキーはerror.constraint.numericです。 指定できるプロパティは以下のとおりです。
|
Required |
リクエストパラメータが必須である(nullや空文字列ではない)という制約を表します。 制約の対象となるのは、valueプロパティで指定されたリクエストパラメータと、アノテーションが付与されているSetterから導き出せるプロパティ名と同名のリクエストパラメータです。 noteキーはerror.constraint.requiredです。 指定できるプロパティは以下のとおりです。
|
TokenRequired |
リクエストパラメータとして渡されたトランザクショントークンがセッションに保持されているものと一致する必要があることを表します。 このアノテーションはクラスまたはアクションメソッドに付与して下さい。 noteキーはerror.constraint.token.tokenRequiredです。 指定できるプロパティは以下のとおりです。
|
ページ固有のバリデーション
独自にバリデーションのためのアノテーションと処理クラスを作成することでアプリケーション固有のバリデーションを実現することができますが、ページ固有のバリデーションの場合はわざわざアノテーションと処理クラスを作るのは大変です。そこでYmirでは、ページ固有のバリデーションをPageクラス内に書くことができるようになっています。
具体的には、返り値がorg.seasar.ymir.message.Notesであるようなメソッドまたはorg.seasar.ymir.constraint.ValidationFailedExceptionをスローするような返り値がvoidであるメソッドをPageクラスに追加して、org.seasar.ymir.constraint.annotation.Validatorアノテーションを付与することで、そのメソッドがバリデーションの際に呼び出されるようになります。
形式1:
@Validator public Notes validate() { if ([バリデーション失敗]) { return new Notes().add([リクエストパラメータ名], new Note( Constraint.PREFIX_MESSAGEKEY + [バリデート種別], new Object[]{ [リクエストパラメータ名] })); } else { return null; } }
形式2:
@Validator public void validate() throws ValidationFailedException { if ([バリデーション失敗]) { throw new ValidationFailedException( new Notes().add([リクエストパラメータ名], new Note( Constraint.PREFIX_MESSAGEKEY + [バリデート種別], new Object[]{ [リクエストパラメータ名] }))); } }
バリデーションに失敗した場合は、返り値またはValidationFailedExceptionのコンストラクタの引数として、失敗情報に対応するNoteオブジェクトを含むようなNotesオブジェクトを指定するようにして下さい。バリデーションに成功した場合は、返り値がNotesのメソッドの場合は空のNotesオブジェクトを返すかnullを返すようにして下さい。
バリデータメソッドが引数を持つ場合は、引数の値が解決されます。この時、リクエストされたアクションがボタンに関連付けられている場合はボタン名に埋め込まれているパラメータがデフォルトの引数値として使用されます。メソッドの引数の解決については「アクションメソッドの引数値の解決」を参照して下さい。
例えばbutton[10][delete]というボタンが押されてPOSTリクエストが送られてきた場合、以下のメソッドのrequestにはHttpServletRequestオブジェクトが、idには10が、typeには"delete"が代入されます。
@Validator public void validate(@Resolve HttpServletRequest request, int id, String type) { .... }
@Validatorアノテーションは複数のメソッドに付与することができます。また、あるアクションが呼び出される時だけバリデーションメソッドを動作させたい場合は、アノテーションの引数としてアクションメソッド名を列挙して下さい。アクションメソッド名を指定しない場合は全てのアクションに関してバリデーションが有効になります。