Struts1 [Validator]
Validator はアクションフォームの検証を外部で行うプラグイン機能です。コレによりDynamicActionForm の
メリットを享受しつつ、検証機能が有効になります。DynaValidatorForm クラスを使う事になります。前回のサンプル(bbs01.war) をベースに、実装してゆきます。bbs02 として使います。今回のサンプル(bbs02.war)
更新日 2016-02-13
DynaValidatorForm に置き換える
まずDynaVidatorForm をアクションフォームとします。次に
設定の編集
/WEB-INF/struts-config.xml にDynaValidatorForm のインスタンスを設定します。
<form-beans>
<!-- 追加 -->
<form-bean name="bbs_dvf"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="str" type="java.lang.String" />
</form-bean>
</form-beans>
次にこのアクションフォームを使うようaction エレメントの設定を修正します。
<action path="/bbs"
type="mypackage.bbsAction"
name="bbs_dvf"
scope="request"
validate="true"
input="/error.jsp">
<forward name="success" path="/bbs.jsp"/>
<forward name="error" path="/error.html"/>
</action>
validate 属性をtrueにし、input 属性にはエラー時にフォワードする先のJSP を設定します。
最後にValidator を機能させる為に、プラグインとして設定しておきます。
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
アクションクラスの修正
フォームにアクセスする際のキャストをDynaActionForm からDynaValidatorForm に変更する。
DynaValidatorForm のimport も忘れずに。文字列がゼロの時の処理はDynaValidatorForm に任せる
為、除去します。
// Compile command. You must be current file's directry.
// javac -classpath "../lib/struts.jar;../../../../common/lib/servlet-api.jar;"
-d "." bbsAction.java
package mypackage;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.DynaActionForm;
import org.apache.struts.validator.DynaValidatorForm; // 追加
public class bbsAction extends Action
{
public ActionForward execute
(
ActionMapping mapping,
ActionForm form,
HttpServletRequest req,
HttpServletResponse res
)
throws Exception
{
// アクションフォームにアクセスできます。
DynaValidatorForm myForm = (DynaValidatorForm)form; // 修正
return mapping.findForward( "success" );
}
}
validation.xml を/WEB-INF に新規作成
Validator プラグインが読み込む、検証の為の設定ファイルを自作します。
<?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>
<form name="bbs_dvf">
<field property="str" depends="required">
</field>
</form>
</formset>
</form-validation>
エラー時のページ(error.jsp) を作成
action の設定でinput 属性に設定した/error.jsp ファイルを作成します。
<%@page contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<html:html locale="true">
<head>
<title>error.jsp</title>
</head>
<body>
<h3>Error!!</h3>
<div>
<html:errors />
</div>
</body>
</html:html>
bbs.jsp の修正
bean:write のname 属性をbbs_dvf(DynaValidatorForm インスタンス名)に修正します。
ブラウザで表示して、bbs01 の時と変わらない事をご確認ください。テキストボックス見入力で
実行を押すと、error.jsp が表示されます。{0} is required. と表示されたら成功です。
エラーメッセージを変更する。
デフォルトのエラーメッセージの変更(errors.required 等)、それに対する一部上書き({0} とarg0)、
そして対象プロパティ毎に独自のエラーメッセージの割り当ての三つの方法があります。
前者の二つの組み合わせだけで相当をカバーできますが、それに囚われない方法も可能という事です。
下準備
エラー時のメッセージはメッセージリソースというテキストファイルに記述されています。struts-config.xml の
message-resources エレメントのparameter 属性がソレです。デフォルトではMessageResources となっており、
該当するファイル(MessageResources.properties) が/WEB-INF/classes に存在しています。
struts-config.xml を修正します。今回はbbs_MR_ja.properties というファイルを新たに用意して参照させます。
<!-- ======================= Message Resources Definitions -->
<!-- parameter 値を変更 -->
<message-resources parameter="bbs_MR"/>
.properties はもちろん、ロケール識別子(_ja) も省略されている事に注意して下さい。これらは言語毎にファイルを
別に準備できる事を示しています。ファイルは/WEB-INF/classes 以下に配置でき、ロケーションパスが深くなる場合は
Java のパッケージのようにドットで区切って表記します。(例:/WEB-INF/classes/filter/bbs_MR_ja.properties なら
filert.bbs_MR )
なおロケール識別子は_ja です。_jp では動きません!間違えやすいので注意!
メッセージリソースとは?
言語ロケール識別子 + .properties という形で終わるファイルで、Java で管理されるリソースです。Web アプリでは
クライアントの希望するロケールでリソースを切り替える事で多言語化を可能にしています。メッセージリソースは
JSP から簡単に参照でき、html:message タグで取り出せます。一つのJSP ファイルで複数の言語ロケールに応じる事が
できる訳です。
デフォルトのエラーメッセージの変更
次に今回はbbs_MR_ja.properties でした。まず下書きとしてbbs_MR というファイル名で作成して以下の内容を書きます。
errors.required={0} は入力必須項目です。
Java ではマルチバイト文字列はUnicode で扱っているので、そのバイトコードをプレフィックス\ を付けて
ワード毎に書き直します。その為のコマンドがnative2ascii でJavaSDK に入ってます。以下のコマンドで実行します。
native2ascii bbs_MR bbs_MR_ja.properties
bbs_MR_ja.properties が以下の内容で作成されてる事を確認して下さい。
errors.required={0} \u306f\u5165\u529b\u5fc5\u9808\u9805\u76ee\u3067\u3059\u3002
Tomcat を再起動します。何も入力せずに実行ボタンを押すとerror.jsp に遷移し、<html:errors /> によって
「{0} は入力必須項目です。」と出力されます。
メッセージ中の{0} に文字を割り当てる。
メッセージリソース中の{0} には、validation.xml で設定しておいた文字列を実行時に割り当てる事ができます。
arg0, arg1, arg2 の三つのエレメントをfield エレメントに配置でき、それぞれが{0}, {1}, {2} に対応します。
<form-validation>
<formset>
<form name="bbs_dvf">
<field property="str" depends="required">
<!-- 追加 -->
<arg position="0" key="text-box" resource="false" />
</field>
</form>
</formset>
</form-validation>
これで実行時には「text-box は入力必須です。」との出力になります。key に文字列を直接書いているので、resource 属性を
false としています。そしてメッセージリソースファイルにmytextbox.text=名前 と準備してあるなら、arg のkey 属性に
"mytextbox.text" として、resource 属性を除けばいいわけです。なお文字列を直接記述できるといっても、日本語等は扱え
ません。その場合は、やはり外部メッセージリソースに記述する訳です。
注意
struts1.2 からはarg0〜arg3 は非推奨になりました。arg タグにposition 属性を用います。
さらに別途に作成したvar エレメントの値を参照するようkey 属性に指示する事もできます。
<form-validation>
<formset>
<form name="bbs_dvf">
<field property="str" depends="required">
<!-- key 属性を修正 -->
<arg0 key="${var:min}" resource="false" />
<!-- 追加 -->
<var>
<var-name>min</var-name>
<var-value>5</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
${var:min} は文字列ではなく、同じ親エレメントに属するvar エレメントのvar-name に該当するソレを参照していると見なされます。
そしてその値(var-value エレメント)を出力します。required の時は単なる二度手間で意味無いのですが、別の検証ルール
においてはvar エレメントによって検証の為のしきい値が設定されたりするので、arg0 とva-vavlue にそれぞれ同じ値を設定するより
var-value を参照させた方が保守性が高まる訳です。
検証対象のプロパティ毎にメッセージを変える。
errors.required は未入力チェックのデフォルトのエラーメッセージなので、変更すると同じWeb アプリ内の別のアクション
の検証においても反映されてしまいます。そこでerrors.required とは違う名前でメッセージを準備しておき、
個別にそれを適用させます。msg エレメントがそれです。
<form-validation>
<formset>
<form name="bbs_dvf">
<field property="str" depends="required">
<!-- 追加 -->
<msg name="required" key="NameTextBox.text" />
<arg0 key="text-box" resource="false" />
</field>
</form>
</formset>
</form-validation>
これでアクションフォームのプロパティstr のrequired 検証時に限って、errors.required では無くNameTexBox.text が
用いられる事になります。もちろんメッセージリソースに「NameTextBox.text={0} を入力して下さい」等の記述も忘れずに。
検証パターンいろいろ
DynaValidatorForm では以下の検証ルールが存在し、アクションフォームのプロパティそれぞれに一つまたは組み合わせて
適用させる事ができます。その指示は/WEB-INF/validation.xml に記述します。
required
値がnull もしくは空白文字の場合にエラーとなります。デフォルトのエラーメッセージはerrors.required です。
<field property="str" depends="required">
<arg0 key="名前" resource="false" />
</field>
requiredif
required と同じ検証ルールですが、他のプロパティ値が指定の条件と合致した場合に適用されます。以下の例では、
プロパティ名check の値が1である場合に限りrequierd 検証を行っています。n は0 から始まる数です。複数定義する時は、その都度この数値をす。
<field property="str" depends="requiredif">
<arg0 key="名前" resource="false" />
<var>
<var-name>field[n]</var-name>
</var-value>check<var-value>
</var>
<var>
<var-name>fieldTest[n]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[n]</var-name>
<var-value>1</var-value>
</var>
</field>
field にはプロパティ名、fieldTest には条件(NULL, NOTNULL, EQUAL)、
fieldValue にはチェックの為の値、 fieldJoin には複数の条件時における
AND もしくはOR の設定(fieldJoin 無しの場合はAND)。
minlength, maxlength
文字数をチェックします。例えば2文字以上、10 文字以下の場合。
<field property="str" depends="minlength,maxlength">
<arg1 key="${var:minlength}" resource="false" />
<arg2 key="${var:maxlength}" resource="false" />
<var>
<var-name>minlength</var-name>
</var-value>2<var-value>
</var>
<var>
<var-name>maxlength</var-name>
</var-value>10<var-value>
</var>
</field>
arg1 とarg2 でメッセージリソース中の{1} ならびに{2} に置き換えられる文字列を設定
しています。それも${} を用いて変数(var) の値を参照するようにしています。
それぞれ${var:minlength}(この場合は2)、${var:maxlength}(この場合は10) に置き換えられわけです。
min, max
文字列を数値に変換し、それぞれの最小値・最大値と比較検証します。例えば、-100 から100 の
範囲であるべきなら。
<field property="str" depends="min,max">
<arg1 key="${var:min}" resource="false" />
<arg2 key="${var:max}" resource="false" />
<var>
<var-name>min</var-name>
</var-value>-100<var-value>
</var>
<var>
<var-name>max</var-name>
</var-value>100<var-value>
</var>
</field>
byte, short, int, long, float, double といった型で範囲を指定する事もできます。
mask
正規表現を使ったマッチング検証です。例えばA で始まる文字列のときはA.* と書きます。
<field property="str" depends="mask">
<var>
<var-name>mask</var-name>
</var-value>A.*<var-value>
</var>
</field>
メールアドレスの形式であるかチェックします。
<field property="str" depends="email">
</field>
date
日時の形式であるかチェックします。Strict の方は文字列長も合致しないといけません。
<field property="str" depends="date">
<var>
<var-name>datePatternStrict</var-name>
</var-value>yyyy-mm-dd<var-value>
</var>
</field>
JavaScript による入力チェックを自動生成する
html:javascript タグを用いると検証ルーチンをJavaScript で生成してくれます。そして
html;form のonsubmit 属性に上記のスクリプトを呼び出す記述を書けばOKです。便利ですね。
bbs.jsp の編集
<%@page contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<html:html locale="true">
<head>
<title>bbs.jsp</title>
<html:javascript formName="bbs_dvf" />
</head>
<body>
<div>
<html:form action="/bbs" method="POST"
onsubmit="return validateBbs_dvf(this);">
<html:text property="str" size="20" />
<html:submit property="submit" value="実行" />
</html:form>
</div>
<pre><bean:write name="bbs_af" property="all" scope="request" /></pre>
</body>
</html:html>
自動生成されたスクリプトの関数名はvalidate + フォーム名(先頭は大文字) です。引数にthis を
渡します。