Cubby ではフォームから入力された値をバリデーションする仕組みが用意されています。
フォームから入力された値は HttpServletRequest#getParameterValues で返される値が String の配列であることからもわかるように、 全ての値を配列として取得できます。定義済みのバリデーションはこの配列に対してのバリデーションを行います。
また、フォームオブジェクトやデータベースを参照してデータ制約を検証する独自のバリデーションをプログラム上に定義することができます。
バリデーションの実行タイミングはリクエストからアクション実行までのフローを参照してください。
バリデーションの定義は Java コードで記述します。以下のように、アクションメソッドに対してバリデーションのルールを定義します。
以下のようにDefaultValidationRulesを継承して、 initializeメソッドをオーバーライドし、そのメソッドの中で addメソッドを用いて フォームのフィールドごとにバリデーションのルールを追加します。
public class LoginAction extends Action { // バリデーションのルール public ValidationRules validationRules = new DefaultValidationRules() { @Override public void initialize() { // フィールド "userId" は必須入力で最大10文字まで add("userId", new RequiredValidator(), new MaxLengthValidator(10)); // フィールド "password" は必須入力で最大10文字まで add("password", new RequiredValidator(), new MaxLengthValidator(10)); } }; ...
入力検証でエラーを検出した場合は、アクションのプロパティerrorsにメッセージが設定され、errorPageで指定されたエラーページへフォワードで遷移します。
// プロパティ「validationRules」をバリデーションのルールとして使用します。 // 検証エラー発生時は「confirm.jsp」に遷移します。 @Validation(rules = "validationRules", errorPage = "confirm.jsp") public ActionResult save1() { ... } }
Cubby に定義済みのバリデーションクラスは以下のものがあります。
ScalarFieldValidator を実装しているクラスがひとつの要素を検証するバリデータ、 ArrayFieldValidator を実装しているクラスが配列全体を検証するバリデータとなっています。
クラス名 | 説明 |
---|---|
ArrayMaxSizeValidator | 配列の最大サイズを検証します。 |
ArrayMinSizeValidator | 配列の最小サイズを検証します。 |
DateFormatValidator | 日付に対する検証を行います。 |
EmailValidator | Eメールアドレスに対する検証を行います。 |
EqualsValidator | 指定した文字列と等しいかどうかを検証します。 |
FileRegexpValidator | ファイルアップロードのファイル名が指定された正規表現にマッチするか検証します。 |
MaxLengthValidator | 最大文字数を検証します。 |
NumberValidator | 数値かどうかを検証します。 |
RangeLengthValidator | 文字列の長さの範囲を指定して検証します。 |
RangeValidator | 数値の範囲を指定して検証します。 |
RegexpValidator | 指定された正規表現にマッチするか検証します。 |
RequiredValidator | 必須検証します。 |
TokenValidator | 2重サブミットを検証します。 |
詳細はAPIドキュメントをご覧下さい。
バリデーションのエラーメッセージは以下のルールで作成されます。
public class LoginAction extends Action { // 項目のメッセージキーを指定 public ValidationRules validation = new DefaultValidationRules() { @Override public void initialize() { // メッセージキー"userId"の値がエラーメッセージ中の項目名として使用されます。 add("userId", new RequiredValidator(), new MaxLengthValidator(10)); // メッセージキー"login.password"の値がエラーメッセージ中の項目名として使用されます。 add("password", "login.password", new RequiredValidator(), new MaxLengthValidator(10)); } }; // 項目名のメッセージキーのプリフィックスを指定 public ValidationRules validation2 = new DefaultValidationRules("login.") { @Override public void initialize() { // メッセージキー"login.userId"の値がエラーメッセージ中の項目名として使用されます。 add("userId", new RequiredValidator(), new MaxLengthValidator(10)); } }; // 各バリデーションにメッセージキーを指定 public ValidationRules validation3 = new DefaultValidationRules() { @Override public void initialize() { // メッセージキー"err.myrequired"がエラーメッセージとして使用されます。 add("password", new RequiredValidator("err.myrequired")); } }; ... }
ほとんどが同じでいくつかの項目が異なる複数のルールを作りたい場合、以下のように他のルールをコピーして使用することができます。
public class LoginAction extends Action { // ベースのルール private ValidationRules baseValidationRules = new DefaultValidationRules() { @Override public void initialize() { add("userId", new RequiredValidator(), new MaxLengthValidator(10)); add("password", "login.password", new RequiredValidator(), new MaxLengthValidator(10)); } }; // ベースのルールに「nickname」の検証を追加 public ValidationRules validationRules1 = new DefaultValidationRules() { @Override public void initialize() { // baseValidationRulesのルールをコピーして追加 addAll(baseValidationRules); add("nickname", new RequiredValidator(), new MaxLengthValidator(10)); } }; // ベースのルールに「password2」の検証を追加 public ValidationRules validation2 = new DefaultValidationRules() { @Override public void initialize() { // baseValidationRulesのルールをコピーして追加 addAll(baseValidationRules); add("password2", new RequiredValidator(), new MaxLengthValidator(10)); } }; ... }
アクションメソッドでエラーを検出した場合は ValidationException をスローすることで、処理を中断してエラーページへ遷移させることができます。
DefaultValidationRules はバリデーションエラーが検出された場合にエラーページへフォワードします。 この挙動はDefaultValidationRules.html#fail(java.lang.String)メソッドに定義されています。 これをオーバーライドすることでエラー発生時の挙動を変更することができます。
public ValidationRules validationRules = new DefaultValidationRules() { @Override public void initialize() { ... } @Override public void fail(String errorPage) { // クライアントに 404 Not Found を返す return new SendError(404); } };
リクエストパラメータのバリデーションを独自に作成するにはScalarFieldValidator またはArrayFieldValidatorを実装して作成します。
実装の方法はそれぞれのインターフェイスの実装クラスを参照してください。
データベースアクセスなどのユーザー作成のロジックによるバリデーションを作成するにはValidationRuleを実装して作成してください。
バリデーションルールを登録する際には add メソッドの第一引数でバリデーションを実行するフェーズを指定できます。
バリデーションはフェーズごとに実行されます。 あるフェーズのバリデーションでエラーがあった場合は次のフェーズのバリデーションを実行せずにエラー処理へ移行します。
デフォルトでは DATA_TYPE(データ型を検証するフェーズ) と DATA_CONSTRAINT(データ上の制約を検証するフェーズ) が定義されていて、 フェーズを指定しない場合は DATA_TYPE のフェーズに追加されます。
public UserDao userDao; public String userId; public String password; public Map<String, Object> sessionScope; public ValidationRules loginValidation = new DefaultValidationRules( "login.") { @Override public void initialize() { add("userId", new RequiredValidator()); add("password", new RequiredValidator()); // userId と password の双方が入力されたことが確認されてから UserValidationRule // を実行したいので、フェーズに DATA_CONSTRAINT に指定します。 add(DATA_CONSTRAINT, new UserValidationRule()); } }; private class UserValidationRule implements ValidationRule { public void apply(Map<String, Object[]> params, Object form, ActionErrors errors) throws ValidationException { User user = userDao.findByIdAndPassword(userId, password); if (user == null) { // エラーを検出した時、次のバリデーションを実行しないようにするためには // ValidationException をスローしてください。 throw new ValidationException("ユーザIDかパスワードが違います。", "userId", "password"); } sessionScope.put("user", user); } }
Cubby のバリデーションはリクエストパラメータの名前に対するものなので、基本的にタイプセーフではありません。 入力項目が多い場合など、制約をフィールドやメソッドへのアノテーションで記述するほうが便利なことも多いので、 OVal - the object validation framework と連携してアノテーションベースのバリデーションを行う Cubby OVal Plug-in を用意しています。
このプラグインを使うと、リクエストパラメータがバインドされた後のフォームオブジェクトが OVal によって検証されます。
public class LoginAction extends Action { // バリデーションのルール public ValidationRules validationRules = new DefaultValidationRules() { @Override public void initialize(String resourceKeyPrefix) { //// フィールド "userId" は必須入力で最大10文字まで //add("userId", new RequiredValidator(), new MaxLengthValidator(10)); //// フィールド "password" は必須入力で最大10文字まで //add("password", new RequiredValidator(), new MaxLengthValidator(10)); add(new OValValidationRule(resourcekeyPrefix)); } }; @RequestParameter @NotNull @NotEmpty @MaxLength(10) private String userId; @RequestParameter @NotNull @NotEmpty @MaxLength(10); private String password @Validation(rules = "validationRules", errorPage = "confirm.jsp") public ActionResult save1() { ... }