2013年12月27日金曜日

Teedaでの複合項目のバリデーションをする

今更のTeedaネタですが、フィールドが前後に分かれた郵便番号や3つのプルダウンで構成された年月日フォームに日付チェックをするときのように複数のフィールドに対して、単一のバリデーションを実行する方法を紹介します。

独自バリデータの実装方法を確認する

フィールドが複数に分かれている情報に対してバリデータを適用したい場合、新たに独自のバリデータを実装する必要があります。
独自のバリデータを作成する方法を知らない方は
を参照してください。

バリデータクラス内でバリデーション対象項目以外の項目を参照できるようにする。

バリデーション対象に指定した項目(メンバ変数?)の値はバリデータのvalidateメソッドの第3引数(Object value) で取得することができるので特に意識する必要はないのですが複合項目でのバリデーションの場合、一緒にバリデーションに使用する項目も取得する必要があります。
バリデーション対象項目ではない項目を取得するには、

  1. バリデーションを指定するアノテーションで、取得する項目名を指定できるようにする。
  2. バリデータでアノテーションで指定された項目名を取得できるようにする。
  3. バリデータのvalidateメソッドの第2引数で渡されるUIComponentから指定した項目のUIComponentを取得する
という作業が必要になります。

バリデーションを指定するアノテーションで、取得する項目名を指定できるようにする。

項目指定用の変数を定義しておけば、アノテーションで項目名を指定できるようになります。
package sample.validator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.seasar.teeda.extension.annotation.validator.Validator;
/**
* 指定した入力項目と同じ値が入力されているかを確認するバリデータ
*
* @author hirohito
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@Validator("sameAsTargetValidator")
public @interface SameAsTarget {
/**
* チェックを実行するメソッド
*/
String target() default "";
/**
* メッセージID
*/
String messageId() default "";
/**
* 比較対象となる入力項目
*/
String targetId() default "";
}

これで
@SameAsTarget(targetId="password")
String password2

といった形でバリデーション時に利用する項目名を指定できるようになります。

アノテーションに指定された項目名をバリデータで取得できるようにする。

アノテーションで宣言したのと同じ名前のプロパティを定義するとアノテーションに指定された項目名をバリデータで取得できるようになります。
/**
* 比較対象となる項目
*/
private String targetId = null;
/**
* 比較対象となる項目を設定する
*
* @param targetId 比較対象となる項目
*/
public void setTargetId(String targetId) {
this.targetId = targetId;
}


下記にバリデーション対象項目ではない項目を取得するサンプルソースを記します。

まずはアノテーションの作成から
package sample.validator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.seasar.teeda.extension.annotation.validator.Validator;
/**
* 指定した入力項目と同じ値が入力されているかを確認するバリデータ
*
* @author hirohito
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@Validator("sameAsTargetValidator")
public @interface SameAsTarget {
/**
* チェックを実行するメソッド
*/
String target() default "";
/**
* メッセージID
*/
String messageId() default "";
/**
* 比較対象となる入力項目
*/
String targetId() default "";
}

バリデータのvalidateメソッドの第2引数で渡されるUIComponentから指定した項目のUIComponentを取得する

validateメソッドの第2引数で渡されるUIComponentからfindComponent()を利用して、他のUIComponentを取得することができます。
/**
* 指定したtargetIdのUIComponentを取得する
*
* @param component UIComponent
* @param targetId UIComponentから取得したい項目のId
* @return 指定したtargetIdのUIComponent
*/
protected UIComponent getTargetComponent(UIComponent component, String targetId) {
if (targetId == null) {
throw new EmptyRuntimeException("targetId");
}
UIComponent targetComponent = component.findComponent(targetId);
if (targetComponent == null) {
throw new EmptyRuntimeException(targetId);
}
return targetComponent;
}

上記メソッドを利用して、コンポーネントを取得することができます。
/**
* (non-Javadoc)
*
* @see javax.faces.validator.Validator#validate(javax.faces.context.FacesContext, javax.faces.component.UIComponent,
* java.lang.Object)
*/
@Override
public void validate(FacesContext context, UIComponent component, Object value) {
AssertionUtil.assertNotNull("context", context);
AssertionUtil.assertNotNull("component", component);
if (!isTargetCommandValidation(context, targets)) return;
UIComponent targetComponent = getTargetComponent(component, targetId);
doValidate(context, component, value, targetComponent);
}

0 件のコメント:

コメントを投稿