struts2とseasar2でCRUD処理(validation編)
前回のCRUDアクション作成(struts2とseasar2でCRUD)ではCRUDの操作ができることを確認しましたが、入力値チェックはやっていませんでした。
今回はstruts2のvalidationの仕組みを使って入力値チェックを行います。
struts2では入力値チェックをValidation Interceptorで行います。
http://struts.apache.org/release/2.3.x/docs/validation-interceptor.html
http://struts.apache.org/release/2.3.x/docs/validation.html
このInterceptorでエラーとなった項目がある場合はWorkflow Interceptorで処理され"input"が返されます。
http://struts.apache.org/release/2.3.x/docs/workflow-interceptor.html
エラー時に返される値は、アクションにValidationWorkflowAwareを実装したり、メソッドに@InputConfigアノテーション(参考)を付けることで上書きすることができます。
このためには、ValidationAwareをアクションに実装する必要があります。ActionSupportを使えばすでに実装されています。
バリデーションの指定方法は大きく3種類あります。
前の2つはデフォルトだと必ず処理されます。
両方とも外す場合は、struts.xml(struts-default.xml)でinterceptor-stackを定義する際にdeclarativeパラメータをfalseにする必要があります。
最後のvalidate()はアクションクラスがValidateableを実装している場合に処理されます。ActionSupportでは実装されています。
コレを無効にするには、interceptor-stackの定義でprogrammaticパラメータをfalseにする必要があります。
処理の順序としては(xml,アノテーション)->validate()メソッドの順です。
xmlの設定によるバリデーション
個人的に好みでないので詳細は省略します。
なぜかというと、設定ファイルが増えるのは「Convention Over Configuration」の考え方に反するから。
http://struts.apache.org/release/2.3.x/docs/validation.html
アノテーションによるバリデーション
まず、struts.xmlにあるinterceptor-stackの中身を次のように書き換える必要があります。
これをしないと、save()メソッドにアノテーションをつけている場合に、他の画面にリクエストがあった場合もこのアノテーションが処理されてしまいます。
<interceptor-ref name="validation"> <param name="validateAnnotatedMethodOnly">true</param> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref>
今回は、struts.xmlにまだinterceptor-stackが定義されていなかったので次のように定義しました。
<package name="myapp" extends="convention-default"> <interceptors> <interceptor-stack name="myapp-Stack"> ~~ここはstrutx-default.xmlのdefaultStackの中身をコピーしてvalidationの部分を上の記述に書き換えます~~ </interceptor-stack> </interceptors> <default-interceptor-ref name="myapp-Stack"/> </package>
アノテーションはフィールドに設定する方法とメソッドに設定する方法があります。
もちろん両方使ってもいいんですが、基本的には1つのアクションクラスに複数のメソッド(画面)がある場合はメソッドにのみ設定するのがいいのかなと思います。
詳細は本家をチェックしてください。
http://struts.apache.org/release/2.3.x/docs/annotations.html#Annotations-ValidationAnnotations
今回はcustomerのnameとemailフィールドを必須にします。
アクションクラスとjspファイルを書き換えます。
JspCrudAction
~~略~~ import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator; import com.opensymphony.xwork2.validator.annotations.Validations; ~~略~~ @Validations( requiredStrings = { @RequiredStringValidator(fieldName="customer.name", message="必須項目です"), @RequiredStringValidator(fieldName="customer.email", message="必須項目です") } ) public String save() { ~~略~~ } ~~略~~
jsp-crud-input.jsp
~~略~~ <tr> <td>名前</td> <td><s:textfield name="customer.name" placeholder="名前"/><s:fielderror fieldName="customer.name"/></td> </tr> <tr> <td>E-Mail</td> <td><s:textfield name="customer.email" type="email" placeholder="E-Mail"/><s:fielderror fieldName="customer.email"/></td> </tr> ~~略~~
これで実行すると、名前をemailを入力しない場合にエラーメッセージが表示されるはずです。
表示デザインはイマイチですが、そこはCSSの設定をしてください。
もしくは、strutsタグのテンプレート自体を書き換えることもできます。詳細は省略します(参考)。
validateメソッドによるバリデーション
アクションクラスがValidateableをimplementsしている場合に処理されます。
あるメソッドxxxxが呼ばれる際に処理するメソッドは、validateXxxx()、validateDoXxxx()、validate()です。validateDoXxxx()はvalidateXxxx()がない場合にのみ処理されます。
今回はvalidate()とvalidateSave()を作ってみます。
JspCrudAction
public void validate() { if (StringUtils.isNotBlank(customer.name)) { if (customer.name.length() < 2) { addFieldError("customer.name", "2文字以上が必須です"); } } System.out.println("validate"); } public void validateSave() { if (StringUtils.isNotBlank(customer.email)) { if (customer.email.length() < 4) { addFieldError("customer.email", "4文字以上が必須です"); } } }
これらの処理はStringLengthFieldValidatorでも実現できますが、ここではあえてべた書きしてます。
コレを実行すると、
一覧表示の際と登録の際にvalidate()メソッドが呼ばれているのが分かると思います。
intercepter-stackの設定でinputをexcludeMethodsに指定しているのでinput()メソッドの場合はvalidate()メソッドは呼ばれません。
また、文字数チェックも正しく動いていることも確認できるはずです。
以上