08.妥当性チェック(Validation)について
概要
ここではStruts2の妥当性チェックについて触れてみたいと思います。
設定ファイルの置き場所については、以下を参照ください。
ここでは、設定ファイルによる妥当性チェックの方法と、アノテーションによる方法を書いてみようと思います。
サンプル
サンプルは設定ファイルを記述します。
後でアノテーションに触れますので、まずはこちらをご覧ください。
【Actionクラスのプロパティ】
remarks
user (自作Userクラス)
【Actionの妥当性チェックファイルサンプル】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<!-- 【DTDの注意点】
DOCTYPEは、strutsのDOCTYPEで宣言してください。
www.opensymphony.comで指定すると、UnknownHostExceptionが出ることがあります。
-->
<validators >
<field name="remarks" >
<field-validator type="stringlength">
<param name="minLength">0</param>
<param name="maxLength">10</param>
<message key="errors.stringlength" />
</field-validator>
</field>
<!--
viditor・・・model用の妥当性チェックファイルを利用するタイプ。
appendPrefix・・・モデルのvalidationファイルでfieldの記述に自動的にnameをつける。
下記設定では、trueのとき"id"、falseのとき"user.id"となる。
-->
<field name="user">
<field-validator type="visitor">
<param name="appendPrefix">true</param>
<message/>
</field-validator>
</field>
</validators>
【Struts2の妥当性チェックの雰囲気】
詳しい解説は以降で記述するとして、ここではStruts2の妥当性チェックの雰囲気に触れてみたいと思います。
上記のように、Struts1と似たような形式で記述します。
アノテーションで記述する場合も、できることや、設定時に使用する名称などがほぼ同じになります。
例えば上記サンプルでの、typeに設定している"stringlength"という妥当性チェック名(type名)は同じになります。
設定ファイル方式の説明
チェック対象
Struts2の妥当性チェックの対象はActionのプロパティ(setter)です。
プロパティは、Javaが既存で持っているクラスやプリミティブな型(例: int, longなど)でも、自作のクラスでも構いません。
チェック内容について
field-validatorタグを見てください。type属性に"stringlength"を設定しています。
これは、文字列の長さをチェックする妥当性チェックです。
type属性には、どのような妥当性チェックを行うかを設定します。
妥当性チェックは、それぞれ設定値を持っています。上記でいうと、"minLength"などです。
これらの値を設定することで、自分に合った妥当性チェックにすることができます(例:最大文字数:10、最少文字数:0 など)。
では、ある妥当性チェックに、どのような設定値があるのかは、どのように調べたらよいのでしょうか?
実は妥当性チェックの型(type)に対応したクラスがあるので、そのsetterをJavaDocで調べるとわかります。
例えば以下のJavaDocを見てみてください。
以下のように記述されています。
fieldName - The field name this validator is validating. Required if using Plain-Validator Syntax otherwise not required
maxLength - The max length of the field value. Default ignore.
minLength - The min length of the field value. Default ignore.
trim - Trim the field value before evaluating its min/max length. Default true
これが設定値になります。
参考までに、以下にtypeの一覧を載せます。
【妥当性チェックの型(type)の一覧】
required ・・・com.opensymphony.xwork2.validator.validators.RequiredFieldValidator
requiredstring ・・・com.opensymphony.xwork2.validator.validators.RequiredStringValidator
int ・・・com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator
long ・・・com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator
short ・・・com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator
double ・・・com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator
date ・・・com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator
expression ・・・com.opensymphony.xwork2.validator.validators.ExpressionValidator
fieldexpression ・・・com.opensymphony.xwork2.validator.validators.FieldExpressionValidator
email ・・・com.opensymphony.xwork2.validator.validators.EmailValidator
url ・・・com.opensymphony.xwork2.validator.validators.URLValidator
visitor ・・・com.opensymphony.xwork2.validator.validators.VisitorFieldValidator
conversion ・・・com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator
stringlength ・・・com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator
regex ・・・com.opensymphony.xwork2.validator.validators.RegexFieldValidator
conditionalvisitor ・・・com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator
※visitor, conversionについては、以下の章で扱います。
妥当性チェックのconversionタイプについて
conversionタイプは少し分かりにくいので、少し説明を加えようと思います。
妥当性チェックのconversionタイプは、型変換エラーを妥当性エラーとして扱いたい場合に設定します。
型変換エラーは、リクエストパラメタが"abc"のような文字列で、それをintのような変換できない型に設定しようとすると発生します。
Struts2は型変換エラーががあると、内部でどのプロパティでエラーが発生したかを保持します。
そして、妥当性チェックのvisitorなどで使用されます。
【使用できるconversionの設定値】
•fieldName - プロパティ名
•repopulateField - 型変換エラーが発生したときに、元の文字列をJSPに出力するかどうか?
何も設定しなければ、int型であれば初期値"0"がJSPに出力されますが、
trueを設定すればJSPには"abc"が出力されます。
※注意点:
実はデフォルトのinterceptorにも似たような機能(conversionError Interceptor)があるため、2重で型変換エラーが出力されます。
⇒次を参照: 82.参考: Struts2トラブルシューティング
自作クラスの場合の妥当性チェックの方法(visitorタイプ等)
方法は、主に2つの方法があります。
【自作クラスチェックの方法1 (自作クラスがUserの場合)】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators >
<!-- String ⇒ int 型変換エラー時のメッセージ -->
<validator type="conversion" short-circuit="true">
<param name="fieldName">age</param>
<param name="repopulateField">true</param>
<message key="errors.int" />
</validator>
<!-- プロパティの妥当性チェック -->
<field name="name" >
<field-validator type="stringlength">
<param name="minLength">3</param>
<param name="maxLength">10</param>
<param name="trim">true</param>
<message key="errors.stringlength" />
</field-validator>
</field>
<field name="age" >
<field-validator type="int">
<param name="min">20</param>
<param name="max">30</param>
<!-- messageタグの間にキーが見つからないときのデフォルト値を設定することもできます。 -->
<message key="errors.IntRange">${min}~${max}の数値を入力せよ</message>
</field-validator>
</field>
</validators>
自作クラスの妥当性チェックを作ります。
アノテーションの場合は、自作クラス(User)のsetterに直接記述します。
そして、Actionクラスには、visitor型の妥当性チェックを設定します。
<Actionの妥当性チェックの設定の再掲>
<field name="user">
<field-validator type="visitor">
<param name="appendPrefix">true</param>
<message/>
</field-validator>
</field>
visitor型は、setterの型(上記の場合はUserクラス)を調べて、Userクラスの妥当性チェックの設定を探しに行きます。
Userクラスの妥当性チェックをファイルで記述する場合は、同じパッケージ階層に置く必要があります。
もし、Userのようなモデルクラスのパッケージの場所と同じ場所に、Struts2の妥当性チェックファイルを置きたくない場合、
srcフォルダの他にresourceフォルダのようなものを作成して、その配下に同じパッケージを作って、そこにおけば良いと思います。
【使用できるvisitorの設定値】
•fieldName - プロパティ名
•context - 妥当性チェック設定ファイル名を探すときにプレフィックスをつけます。オプションです。
何も設定しなければ、"User-validaiton.xml"を探しに行きますが、
例えば"xxx"を設定すると、"User-xxx-validation.xml"を探しに行きます。
•appendPrefix - 上記の場合、trueのとき"id"、falseのとき"user.id"となります。
つまり、プロパティ名をプレフィックスとしてつけるかどうかを指定します。オプションです。
【自作クラスチェックの方法2 (自作クラスがUserの場合)】
<field name="user.name" >
<field-validator type="stringlength">
<param name="minLength">3</param>
<param name="maxLength">10</param>
<param name="trim">true</param>
<message key="errors.stringlength" />
</field-validator>
</field>
Actionクラスの妥当性チェックのファイルに、上記のように”user.”を記述したfieldタグを追加するだけです。
ここではuser.ageなど他のUserクラスのプロパティを記述しませんが、同様に追記すれば妥当性チェックが行えます。
Struts2の妥当性チェックでは、階層のプロパティ(例:"user.name")も使用できます。
新たな自作の妥当性チェックを追加する方法のサンプル
「ひらがな」かどうかをチェックするなどの、新たな妥当性チェックを追加する方法を見ていきます。
では、サンプルとして、BigDecimalクラスの妥当性チェックを作ってみましょう。
<Abstract妥当性チェッククラスのサンプル>
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public abstract class AbstractFieldValidator<T> extends FieldValidatorSupport {
@SuppressWarnings("unchecked")
@Override
public void validate(Object val) throws ValidationException {
// Validation対象パラメータ
String field = getFieldName();
// 対象パラメータ
T value = (T)getFieldValue(field, val);
if ( !validateInternal(field, value) ) {
addFieldError(field, val);
}
}
abstract protected boolean validateInternal(String fieldName, T value) throws ValidationException ;
}
無理して上記のような基底クラスを作る必要はありません。
しかし、複数の妥当性チェッククラスを作る場合は便利だと思います。
<BigDecimal妥当性チェッククラス>
import java.math.BigDecimal;
import com.opensymphony.xwork2.validator.ValidationException;
public class BigDecimalFieldValidator extends AbstractFieldValidator<BigDecimal> {
private String min;
private String max;
//accessor------------------------------------------
public void setMin(String min) {
this.min = min;
}
public String getMin() {
return min;
}
public void setMax(String max) {
this.max = max;
}
public String getMax() {
return max;
}
//---------------------------------------------
@Override
protected boolean validateInternal(String fieldName, BigDecimal value)
throws ValidationException {
BigDecimal validFrom, validTo;
validFrom = new BigDecimal(this.min);
validTo = new BigDecimal(this.max);
//チェック
if(value == null) return true;
if(value.compareTo(validFrom) < 0){
return false;
}
if(value.compareTo(validTo) > 0){
return false;
}
return true;
}
}
実装自体は、FieldValidatorSupport をextendsして、validate()メソッドを記述するだけです。
validate()メソッドは基底クラスで記述しましたので、validateInternal()メソッドを実装すればよいことになります。
ちなみに、setter/getterは妥当性チェックの設定値になります。
また、メッセージリソースの中でも、${min}のようにOGNL式で参照することができます。
<src/validators.xml のサンプル>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator Config 1.0//EN"
"http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd">
<validators>
<validator name="dec" class="validator.BigDecimalFieldValidator"/>
</validators>
<validation.xml の設定サンプル>
<field name="user.fee" >
<field-validator type="stringlength">
<param name="min">10.1</param>
<param name="max">22.5</param>
<message key="errors.number" />
</field-validator>
</field>
アノテーション方式の説明
アノテーションの場合も、考え方は設定ファイルと同じです。
ですので、まず上記の設定ファイルの説明をお読みください。
基本的には、記述方法が違うだけです。
以下のように、setterの前に記述するだけです。
@StringLengthFieldValidator(maxLength="10", minLength="0", key="errors.stringlength")
public void setRemarks(String remarks) {
this.remarks= remarks;
}
アノテーションの名称は、設定ファイル方式の妥当性チェックのtype名を途中まで記述して、Ctrl+Spaceキーで
eclipseのアシスト機能を使用すれば自動で出てくるかと思います。
また、複数のtypeを指定したい場合は、setterの前に複数記述するだけです。
参考: http://struts.apache.org/2.3.1/docs/validations-annotation.html
@Validationsについて
@Validationsをクラスや画面処理メソッドに設定して、まとめて妥当性チェックを記述できるようです。
@Validations(
stringLengthFields={@StringLengthFieldValidator(type = ValidatorType.SIMPLE, minLength="10" , maxLength = "12",
fieldName = "remarks", key = "errors.stringlength")}
)
public String doInput() {
return "input";
}
上記では、remarksプロパティだけを記述しましたが、@Validationsの()内で複数記述できます。
クラス全体に対しても記述できますが、setterに記述した妥当性チェックも動作するので、2重にエラーメッセージが出力されます。
ですので、通常は上記のように画面処理メソッドに記述する使い方になると思います。
メソッドに記述すると、複数の画面処理メソッドがある場合、メソッド毎に妥当性チェックを変えられるメリットがあります。
【メソッド毎の妥当性チェックを行う上での注意】
ドキュメントを読んだだけで試していませんが、ValidationInterceptorのvalidateAnnotatedMethodOnlyをtrueにしないといけないようです。
⇒http://struts.apache.org/2.3.1/docs/validations-annotation.html
アノテーション方式で自作妥当性チェックを使用する場合
自作の妥当性チェックを追加する方法は、上記の設定ファイルの方法と同じですので、そちらを参照ください。
使用方法は少し違います。
以下のように記述します。
@CustomValidator(
type = "numericField",
parameters = { @ValidationParameter(name = "min", value = "0"), @ValidationParameter(name = "max", value = "10") },
key = "errors.stringlength"
)
public void setRemarks(String remarks) {
this.remarks= remarks;
}
ちょっと記述量が多くなりますが、設定値も@ValidationParameterで設定できます。
プログラムによる妥当性チェック
プログラムで妥当性チェックを書きたいときは、Actionクラス内のvalidate()メソッドを使用します。
struts.xmlのインターセプターの設定によってはvalidate()メソッドは実行されないので注意してください。
⇒参考: 03.Struts2の設計と設定のルール
【validateメソッドの使用例】
@Override
public void validate() {
if(this.id == null){
addFieldError("id", getText("errors.required", new String[]{"id"}));
}
}
また、もし妥当性チェックエラー時にinput以外の画面を表示したい場合、画面処理メソッド内で妥当性チェックを記述しても良いかもしれません。
以下のサンプルを参照ください。
@SkipValidation
public String doInput() throws Exception {
if(this.id == null){
return "top";
}
return Action.INPUT;
}
設定ファイル方式・アノテーション方式の問題
設定ファイル方式とアノテーション方式のどちらを使用するかは悩むかもしれません。
アノテーションはコードの近くに置くので妥当性チェックをかけているプロパティがすぐ分かります。
しかし、アノテーションはStruts2のものなので、Struts2専用のクラスのようになってしまいます。
かといって、アノテーションでは可能でも、設定ファイルによる方法ではできないこともあります。
(上記の@Validationsの章と、以下の強みを参照)。
ここでは、どのように使っていくかのヒントになるようなものを書いてみたいと思います。
・アノテーションの強み
ただ、アノテーションの場合、Actionの画面処理メソッド毎に記述できるので、より細かな単位で妥当性チェックを記述できるようです。
ファイルによる妥当性チェックの場合、1つのActionクラスに1つしか妥当性チェックファイルを定義できません。
以下も参照ください。
・アノテーションの弱み
しかし、アノテーションの場合、直接クラスのコードに記述しなければならないため、Struts2によってコードが汚されます。
ActionクラスはStruts2専用のクラスなのでまだよいのですが、モデルクラス(POJO)などは微妙です。
Springの妥当性チェックもモデルクラスにアノテーションに記述するものが主流ですので、2つの妥当性チェックが記述され、
読みにくくなる可能性もあります。
Struts2では、アノテーションと設定ファイルの方法を混ぜて使用できるので、
アノテーションを使用したい場合はActionクラスのみにし、モデルの妥当性チェックは設定ファイルにする、などすると良いかも知れません。
Created Date: 2012/03/07