デジタルチャイルド日記

コンピュータ関連のいろいろメモを残していく子供部屋です。

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はプレゼンテーション層)からでも、チェックロジックを呼ぶことができますからね。

 

以上。メモメモでした。