Seasar DI Container with AOP

概要

S2Strutsで利用できるアノテーションを使用したValidationを作成するには

を行います。 この作業について、2つの入力内容が同じかを検証するValidationの作成を通して説明します。

Strutsでの新規Validation作成

Struts(commons validator)としての新規Validationを追加するには、

  • 検証用クラスの作成
  • validator-rules.xmlへ設定情報の追加
を行います。 Struts Validator Guideに、Strutsでの新規Validationを追加する方法が記述されています。 こちらも参考にしてください。

2つの入力内容が同じか検証するクラスは以下のようになります。

package org.seasar.struts.examples.validator;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.util.ValidatorUtils;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.Resources;

public class MyFieldChecks {

    public static boolean validateTwoFields(Object bean,
            ValidatorAction validatorAction, Field field,
            ActionMessages errors, Validator validator,
            HttpServletRequest request) {

        String value = ValidatorUtils.getValueAsString(bean, field.getProperty());
        String sProperty2 = field.getVarValue("secondProperty");
        String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

        if (!GenericValidator.isBlankOrNull(value)) {
            try {
                if (!value.equals(value2)) {
                    errors.add(field.getKey(), Resources.getActionMessage(
                            validator, request, validatorAction, field));

                    return false;
                }
            } catch (Exception e) {
                errors.add(field.getKey(), Resources.getActionMessage(
                        validator, request, validatorAction, field));
                return false;
            }
        }

        return true;
    }
}

最初に検証を行うプロパティの値を取得します。 次にvalidation設定の"secondProperty"変数に指定したプロパティ名を取得しそのプロパティの値を取得します。 最後にその2つの値を比較し、正しい値か確かめています。 ここでは、"secondProperty"という変数が必要になるところがポイントです。 この変数はValidationアノテーションを作成するときのプロパティとして宣言することになるからです。

次に上記のクラスをvalidator-rules.xmlに追加します。 validatorタグのname属性(validator name)に指定する内容は、アノテーション名と関連があります。 S2Strutsでは以下の規則によりアノテーション名を変換しvalidator nameと一致するか判断して特定します。

  • アノテーション名の先頭文字を小文字にする
  • アノテーション名の最後が"Type"で終わっている場合それを除く
例えば、Hogeアノテーションの場合のvalidator nameは"hoge"となり、FooTypeアノテーションの場合のvalidator nameは"foo"となります。

今回はアノテーション名をTwoFieldsとするためnameは"twoFields"とします。validator-rules.xmlへは以下の内容を追加します。

      <validator name="twoFields"
            classname="org.seasar.struts.examples.validator.MyFieldChecks"
               method="validateTwoFields"
         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"
              depends=""
                  msg="errors.twoFields"/>

msg属性に"errors.twoFields"と指定したので、このメッセージKeyをapplication.propertiesに追加します。

errors.twoFields={0} has to have the same value as the confirm field.

ここまでがStrutsでの新規Validation作成作業です。

Validationアノテーションの作成

Validationアノテーションの作成は

  • アノテーションの定義
  • ConfigRegisterの作成
を行います。

S2Strutsの提供するアノテーションは、定数アノテーション、Tigerアノテーション、Backport175アノテーションの3種類があります。 定数アノテーションとして利用する場合はアノテーションの定義は必要ありません。 Tigerアノテーションとして利用する場合は、メタアノテーションとしてorg.seasar.struts.validator.annotation.tiger.ValidatorTargetを指定し以下のように作成します。

package org.seasar.struts.examples.validator.annotation.tiger;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.seasar.struts.validator.annotation.tiger.ValidatorTarget;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ValidatorTarget
public @interface TwoFields {

    String secondProperty();

}

Backport175アノテーションとして利用する場合は、メタアノテーションとしてorg.seasar.struts.validator.annotation.backport175.ValidatorTargetを指定し以下のように作成します。

package org.seasar.struts.examples.validator.annotation.backport175;

/**
 * @org.seasar.struts.validator.annotation.backport175.ValidatorTarget
 */
public interface TwoFields {

    String secondProperty();

}

今回は検証するためにsecondPropertyが必要となるため上記のようになりました。 validation設定で変数が必要ない場合はプロパティを定義する必要はありませんし、これから作成するConfigRegisterは必要ありません。

アノテーションで取得した値はConfigRegisterを作成し設定する必要がありますので、 TwoFieldsConfigRegisterImplを作成します。

TwoFieldsConfigRegisterImplは、org.seasar.struts.lessconfig.validator.config.ConfigRegisterを実装します。 registerメソッドの引数はfieldとparameterです。 fieldは、フィールドに対して行う妥当性チェックとエラーメッセージの生成に使用する入れ替え可能な妥当性チェックのリストとメッセージの情報と値を内部に持ちます。 つまりValidationの内容を格納するオブジェクトです。 parameterは、アノテーションで定義したメソッド名をkey、メソッドの戻り値をvalueとしたMapです。

package org.seasar.struts.examples.validator.config;

import java.util.Map;

import org.apache.commons.validator.Field;
import org.apache.commons.validator.Var;
import org.seasar.struts.lessconfig.validator.config.ConfigRegister;

public class TwoFieldsConfigRegisterImpl implements ConfigRegister {

    public void register(Field field, Map parameter) {
        String secondProperty = (String) parameter.get("secondProperty");

        Var var = new Var();
        var.setName("secondProperty");
        var.setValue(secondProperty);
        field.addVar(var);
    }

}

作成したConfigRegisterはコンポーネントとして登録する必要があります。 登録するときのコンポーネント名は、validator nameのときと同様のアノテーション名変換を行い"ConfigRegister"を付け加えた名前とします。 例えば、Hogeアノテーションの場合は"hogeConfigRegister"となり、FooTypeアノテーションの場合は"fooConfigRegister"となります。

今回はコンポーネントとして登録するために新規でvalidator.dionを作成します。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="twoFieldsConfigRegister"
            class="org.seasar.struts.examples.validator.config.TwoFieldsConfigRegisterImpl"/>
</components>

そしてapp.diconにincludeを追加して、validator.dionを読み込むようにします。

    <include path="validator.dicon"/>

ここまでがS2Strutsでの新規アノテーションの作成作業です。

これでアノテーションを使用したValidation作成作業は完了です。

動作確認

作成したTwoFieldsアノテーションを試すには、

  • Viewの作成
  • Actionの作成
  • Formの作成
を行います。

まずはViewの作成です。ここではJSPをViewとして利用します。確認用のため簡単な作りです。

<%@ page contentType="text/html;charset=Windows-31j" language="java" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://www.seasar.org/tags-s2struts" prefix="s2struts" %>

<html>
<head>
  <title>Two Fields Test</title>
</head>
<body>
  <html:errors />

  <html:form action="/twoFields" method="POST">
    <s2struts:page/>
    <table>
      <tr>
        <td>field</td>
        <td><html:text property="field"/></td>
      </tr>
      <tr>
        <td>confirm field</td>
        <td><html:text property="confirmField"/></td>
      </tr>
    </table>
    <html:submit/>
  </html:form>
</body>
</html>

次はActionの作成です。今回はPOJOのActionで無設定機能(詳細は「無設定S2Strutsリファレンス」を参照)を使います。 Actionのインターフェースと実装は以下のようになります。

package org.seasar.struts.examples.validator;

public interface TwoFieldsAction {
    
    String execute();

}
package org.seasar.struts.examples.validator;

public class TwoFieldsActionImpl implements TwoFieldsAction {

    public String execute() {
        return "success";
    }

}

Actionの処理は"success"を返すだけですがTwoFieldsアノテーションの動作確認には十分です。

Actionはコンポーネントとして登録する必要があります。新規に作成したtwoFields.diconは以下のようになります。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
	"http://www.seasar.org/dtd/components21.dtd">
<components>
	<component name="twoFieldsAction"
			class="org.seasar.struts.examples.validator.TwoFieldsActionImpl"
			instance="request" />
</components>

そしてapp.diconにincludeを追加して、twoFields.diconを読み込むようにします。

    <include path="org/seasar/struts/examples/dicon/twoFields.dicon"/>

最後にFormを作成します。例として定数アノテーションの場合とTigerアノテーションの場合の2つのFormを以下に記述します。 利用するアノテーションでFormを作成してください。

package org.seasar.struts.examples.validator;

import java.io.Serializable;

public class TwoFieldsForm implements Serializable {

    private static final long serialVersionUID = 1L;

    private String field = "";

    private String confirmField = "";
    
    public String getField() {
        return field;
    }
    
    public static final String field_VALIDATOR_0 = "required";

    public static final String field_VALIDATOR_1 = "twoFields, secondProperty = confirmField";

    public static final String field_VALIDATOR_ARGS = "Field, resource=false";

    public void setField(String field) {
        this.field = field;
    }

    public String getConfirmField() {
        return confirmField;
    }

    public static final String confirmField_VALIDATOR = "required";

    public static final String confirmField_VALIDATOR_ARGS = "ConfirmField, resource=false";

    public void setConfirmField(String confirmField) {
        this.confirmField = confirmField;
    }

}
package org.seasar.struts.examples.validator;

import java.io.Serializable;

import org.seasar.struts.examples.validator.tiger.TwoFields;
import org.seasar.struts.validator.annotation.tiger.Args;
import org.seasar.struts.validator.annotation.tiger.Required;

public class TwoFieldsForm implements Serializable {

    private static final long serialVersionUID = 1L;

    private String field = "";

    private String confirmField = "";
    
    public String getField() {
        return field;
    }
    
    @Required
    @TwoFields(secondProperty="confirmField")
    @Args(keys = "Field", resource = false)
    public void setField(String field) {
        this.field = field;
    }

    public String getConfirmField() {
        return confirmField;
    }

    @Required
    @Args(keys = "ConfirmField", resource = false)
    public void setConfirmField(String confirmField) {
        this.confirmField = confirmField;
    }

}

これで確認ができます。 Tomcatを起動して、ブラウザからhttp://localhost:8080/s2struts-example/pages/twoFields.jspにアクセスし動作確認してください。

新規にアノテーションを使用したValidationを作成するのは通常より大変な作業かもしれませんが、一度作成すれば簡単にFormで使えるようになると思います。 作成したときの苦労を十分回収することができるのではないでしょうか?

独自のValidationを作ってみませんか?