入力フォーム画面と複数のチェック
このサンプルでは簡単な入力フォームと、いくつかOValの設定を行ったクラスを紹介します。先ほどの例ではActionクラスに画面からのパラメータと入力チェックを直接記述しましたが、この例では、別のクラスに入力パラメータとOValのチェック設定を行っています。さらに独自チェックロジックを設定する方法も紹介します。
まずはActionクラスです。リクエストパラメータはmodelインスタンスへ自動的にバインドされるように、ModelDrivenインターフェイスを実装しています。OValによる入力チェックをそのクラスに委譲するよう、@AssertValidをmodelフィールドのすぐ上に宣言します。
こうすることで、入力チェックの詳細をmodelフィールドであるSampleModelにて設定します。ですので、Actionクラスではフィールドごとの入力チェックの内容は記載しません。
@Namespace("/oval") @ParentPackage("oval-default") @InterceptorRefs({ @InterceptorRef(value="ovalValidationStack"), }) @Results({ @Result(name="input" , type="dispatcher" , location="success.jsp"), // 入力チェックにかかった場合の画面 @Result(name="success" , type="dispatcher" , location="success.jsp"), // 入力チェックを通過した場合の画面 }) public class SampleAction extends ActionSupport implements ModelDriven<SampleModel>{ /** * 参照のみのアクション。ここでは入力チェックは行われない。 */ @Action("execute") public String browse() throws Exception { return "success"; } /** * 入力チェックが起動するアクション。 */ @Action("check") public String check() throws Exception { return "success"; } /** * 入力パラメータを格納するクラスで、ModelDrivenインターセプタによって自動的に設定。 * 入力チェックの設定を委譲するAssertValidを宣言する。 */ @AssertValid private SampleModel model; /** * @return model */ public SampleModel getModel() { model = new SampleModel(); return model; } }
では続いて、リクエストパラメータを格納し、さらにOValの詳細な設定を行っているSampleModelクラスです。このクラスは、パラメータを格納するフィールドと、対応するset/getメソッドを実装しているものです。OValの設定はフィールドのすぐ上にて宣言します。まずは設定方法とその例を示します。
public class SampleModel { /** * name。Null/空文字を禁止し、長さを6~16文字までに制限する。 * エラーメッセージはerrorCodeで定義。 * さらに入力された名前に関するチェックをValidateWithMethodにて定義。(A) */ @NotNull(message ="usermodel.input.name.require") @NotEmpty(message ="usermodel.input.name.require") @Length(min=6, max=16 ,errorCode="usermodel.input.name.length") @ValidateWithMethod(methodName = "isValidName", parameterType = String.class , message="usermodel.input.name.prohibit") // (A) private String name; /** 入力禁止の名前 */ private String[] prohibitionNames = {"aaa","bbb","ccc","ddd","eee"}; /** * password。Null/空文字を禁止し、長さを8~12文字までに制限する。 * CheckWithで拡張チェックを行う。パスワードが名前に含まれている場合もエラーとする。(B) */ @NotNull(message ="usermodel.input.password.require") @NotEmpty(message ="usermodel.input.password.require") @Length(min=8, max=12 ,errorCode="usermodel.input.password.length") @CheckWith(value=NameAndPasswordCheck.class ,message="usermodel.input.name.containpassword") // (B) private String password; /** * 電話番号。正規表現で定義。 * 数値で2~5文字 - 1~5文字 - 2~5文字のフォーマットに合致していない場合にエラーとする。 */ @NotNull(message="usermodel.input.phone.require") @MatchPattern(pattern={"\\d{2,5}-\\d{1,5}-\\d{2,5}"} , message="usermodel.input.phone.format") private String phone; /** * メールアドレスチェック。 */ @Email(message="usermodel.input.mailAddress.invalid") private String mailAddress; /** * 都道府県。Null/空文字を禁止。 */ @NotNull(message="usermodel.input.pref.require") @NotEmpty(message="usermodel.input.pref.require") private String pref; /** * @return name */ public String getName() { return name; } public void setName(String name) { this.name = name; } …(以下、set/getメソッド)… /** * 入力された名前に関する拡張チェック。(A) * ここでは仮想的に、指定された文字列(prohibitionNames)を含んではいないかをチェックする。 * @param name 入力された値 * @return チェック結果。常にbooleanを返すこと。 */ private boolean isValidName(String name) { for ( String prohibition:prohibitionNames) { // 引数で渡された値が入力禁止の名前に登録されている文字列を含んでいた場合はfalse if ( name.contains(prohibition)) { return false; } } return true; } /** * より複雑な入力チェックを実装したインナークラス。(B) * 複数のパラメータの相互関係チェック、マスターデータなどの他のリソースから取得した値のチェックや、 * 実行時例外をそのままStruts 2へ渡すことなく通常の入力チェックと同等に扱う場合に使われる。 * @author koji.azuma */ private static class NameAndPasswordCheck implements CheckWithCheck.SimpleCheck { /** * 入力された名前にパスワードが含まれていないかをチェックする。 * ※CheckWithCheck必須実装メソッド。 * * @param validatedObject チェック対象インスタンス。 * @param value パラメータ値。 */ public boolean isSatisfied(Object validatedObject, Object value) { // CheckWithCheckを呼び出しているフィールドに指定された値が空でないかをチェックする。 // もし空であればチェック対象にしないので、ここではtrueを返してチェックを行わない。 String nullCheck = (String)value; if ( nullCheck == null || nullCheck.equals("")) return true; // チェック対象フィールドを取り出す String name = ((SampleModel) validatedObject).name; String password = ((SampleModel) validatedObject).password; // ユーザー名にパスワードを含んでいたら入力チェックエラーとする。 // 入力チェックエラー=falseを返す。 return !(name.contains(password)); } } }
OVal Frameworkで初めから提供されているフォーマットチェック以外に、Javaのコードで記述した拡張入力チェック内容は、リスト中の(A)、および(B)に示しました。詳細については後ほど示すことにします。
最後にJSPファイルです。入力フォームとエラーメッセージを自動的に表示させるため、Struts 2タグである<s:>タグを用いています。
<?xml version="1.0" encoding="UTF-8" ?> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <%@ taglib prefix="s" uri="/struts-tags"%> <head> <s:head theme="xhtml"/> </head> <body> <div id="result">以下の項目に入力して「送信する」ボタンを押してみましょう <s:form id="formValidate" action="check" theme="xhtml" cssClass="yform" > <!-- 入力フォームと送信ボタン --> 入力フォーム+Validation<br/> <s:textfield name="name" label="名前"></s:textfield> <s:password label="password" id="password" name="password" label="パスワード"/> <s:textfield label="mailaddress" id="mailAddress" name="mailAddress" label="メールアドレス"/> <s:textfield label="phone" id="phone" name="phone" label="電話番号"/> <s:textfield label="pref" id="pref" name="pref" label="都道府県"/> <s:submit value="送信する" ></s:submit> </s:form> </div> </body> </html>
入力パラメータは<s:tetfield>、パスワードのみ<s:password>を用いて、入力フォームを作成します。
ではこのサンプルを稼動させてみましょう。サンプルアプリケーションをデプロイし、http://127.0.0.1:8080/OValSample/oval/executeをブラウザで参照します。すると次の画面が表示されると思います。
では何も入力せずにそのまま「送信する」ボタンをクリックし、入力チェックを稼動させます。すると次の画面のように、それぞれのパラメータの入力チェックの結果が表示されます。
では次にそれぞれのフォームへ適切な値を入力し、先ほどと同様に「送信ボタン」を押します。
送信ボタンを押すと入力チェックが稼動します。すべてのチェックをパスした場合は同じ画面へ遷移するようにActionクラスで記述しましたので、パスワードを除いた値以外は先ほど記入した値が表示されます(※パスワードは<input type="password">なので、再表示時には自動的にリセットされます)。
基本的な動作が確認できたら、次はより複雑な入力チェックを実装する方法を、サンプルを通して紹介します。