Strutsの独自Validator
先日の続きでvalidatorについて。
Strtusから提供されているValidatorもいろいろありますが、それだけではすべてのチェックを行うことはできません。
その為、どうしても独自のValidatorを作成する必要に迫られることがあります。
独自のvalidtorを追加するのは、意外と簡単で、以下の手順で作成が可能です。
チェック(検証)を行うクラス作成
まずは、チェックを行う処理を追加します。
今回のサンプルは同一名の項目が複数ある場合に、いずれが必須という処理になります。たとえば、都道府県のうち1つは必須など。
詳細は説明はソースのコメントを参照してください。
package jp.co.test.validator; import java.lang.reflect.InvocationTargetException; import javax.servlet.http.HttpServletRequest; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.validator.Field; import org.apache.commons.validator.Validator; import org.apache.commons.validator.ValidatorAction; import org.apache.struts.action.ActionMessages; import org.apache.struts.validator.Resources; public class AreaCheckValidator { /** * チェックのうち1つ以上必須 * ・同名の項目のうち1つ以上が選択されている場合に使用します。 * * @param bean Beanクラス * @param va バリデータアクション * @param field フィールド * @param errors エラーメッセージ * @param v バリデータ * @param request リクエスト * @return チェック結果 */ public static boolean validateSelectOne(Object bean, ValidatorAction va, Field field, ActionMessages errors, Validator v, HttpServletRequest request) { String[] values = {}; // varで指定されたcheckonの値を取得 String onvalue = Resources.getVarValue("checkon", field, v, request, true); try { // プロパティの値を取得(配列の為、PropertyUtils使用) values = (String[])PropertyUtils.getProperty(bean, field.getProperty()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } // 取得したプロパティがない場合は、TRUEを返す。 if(null == values || values.length == 0) { return Boolean.TRUE; } // チェック本体 for(int i=0;i<values.length;i++) { // 値がnullか未入力の場合、値比較しない if ( values[i] != null && values[i].length() != 0 ){ // varで指定された値かどうかチェックする。 if( values[i].equals(onvalue) ){
// チェックOKで終了 return Boolean.TRUE; } } } // 1つも値が一致しない場合、フィールドにエラーメッセージをセット errors.add(field.getKey(), Resources.getActionMessage(v, request, va, field)); // チェックNGで終了 return Boolean.FALSE; } }
【補足】
ちなみに、上のロジックは実用性には欠けますので、そのままでは使えませんので、悪しからず・・・(笑)
クラスを設定(validator-rules.xml)を追加
作成したクラスをvalidator-rules.xmlに追加します。
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation// DTD Commons Validator Rules Configuration 1.1.3//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <form-validation> <global> <validator name="selectOne" classname="jp.co.test.validator.AreaCheckValidator" method="validateSelectOne" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages, org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest" msg="errors.selectOne"/> </global> </form-validation>
validatorの詳細な内容は以下を参照。
属性名 | 説明 |
---|---|
name | チェックの名称。 validation.xmlとの紐づけに使う。 |
classname | チェックロジックのクラス。 |
method | チェックロジックのメソッド名 |
methodParams | チェックロジックのパラメータ。 ※パラメータは一緒なのになぜ指定しているのかが不明。パラメータの方が取れないからか? |
msg | チェックでNGになった場合のデフォルトメッセージ。 ※validation.xmlの設定で上書きされる??? |
※他にもありますが、今回は省略。
validation.xmlに設定を追加
最後に、 validation.xmlにチェックを追加します。
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation// DTD Commons Validator Rules Configuration 1.1.3//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <form-validation> <formset> <field property="checkValue" depends="selectOne"> <var> <var-name>checkon</var-name> <var-value>1</var-value> </var> <msg name="sample" key="errors.selectOne" /> </field> </form> </formset> </form-validation>
これはいつもと同じです。
- checkValueがString[]型で定義すること。
- dependsはvalidator-rules.xmlと合わせて、selectOneとすること
- varで、checkonとして、ON状態の値を設定すること。
ぐらいですかね。
個人的には
個人的にですが、開発時にはドメインやエンティティが確定した段階で、検証ロジックは作成するほうがいいかなと思っています。そのほうが、開発(実装)への着手が早くなり、問題点の洗い出しや実装イメージが早く固まることが予想されるからです。
また、単体のテストとしても早く取り掛かることができる為、時間的にもゆとりがでるようになると思います。
実際のチェックロジックの実装は、validator内には置かず、別途チェッククラスを作成して、validatorからはそのロジックを呼ぶようにするほうがいいでしょう。こうすることで、どのレイヤ(Strutsのvalidatorはプレゼンテーション層)からでも、チェックロジックを呼ぶことができますからね。
以上。メモメモでした。