Upload
eiryu
View
1.156
Download
4
Embed Size (px)
Citation preview
Javaでのバリデーション〜Bean Validation篇〜
2014/12/04 Validation Night at Line@eiryu
なにをやっているのか
● Twitter @eiryu○ http://eiryu.com
● 仕事○ インフラ・情シス
● バッググラウンド○ Webアプリケーションエンジニア
■ Java● Spring Framework
■ Groovy■ JavaScript■ PostgreSQL
なにをやっているのか
なぜやるのか
● 人間なのでヒューマンエラーは付きもの● バリデーションされてなかったことによる壊れた
ユーザーデータはマーケティングにも生かせない○ 男性で妊娠している等
● Webアプリケーションの場合、最悪ユーザー情報が漏洩したり、操作されたりする
どうやってやっているのか
● Bean Validationを利用● Webアプリケーションのコントローラでユーザー
入力をチェック● 単体テスト(JUnit)で想定しうる不正な入力のテ
スト
※フレームワークはSpring Bootを利用
こんなことやります
Bean Validationで(ry
以上、Wantedly四段活用でした!
Bean Validationとは
“JavaBeansのバリデーション(値の検証)のため
のメタデータモデルとAPIを定めたJavaのソフトウェアフレームワーク”
Wikipedia
http://beanvalidation.org/
Bean Validationの沿革
2009 Bean Validation 1.0(JSR 303)2013 Bean Validation 1.1(JSR 349)
JSRとは
Java Specification Requestsの略。日本語だと、Java仕様要望。個人的にはJava版のRFCと捉えている。
何がうれしいのか
● あらかじめよく使う制約(チェック)が用意されている○ Constraintsと呼ぶ
● ユーザーの入力を受け取るJavaBeans(POJO)にアノテーションで記載するため、POJOに対してテストが書ける○ コントローラのメソッド内でチェックしているとリクエストを
エミュレートするテストを書かなければならない
Constraintsの例
● @NotNull○ nullでないこと
● @Pattern○ 指定した正規表現にマッチすること
● @Size○ 文字列等のサイズが指定した範囲であること
● @AssertTrue○ trueであること
● @Future○ JVMの現在日時より未来であること
packageはjavax.validation.constraints
ここで一般的なバリデーションの話に戻ると。。
バリデーションの種類
● 単項目チェック● 相関チェック
単項目チェック
● 1つの項目に対するチェック● 例
○ ユーザー登録で名前の入力は必須だが、入力されてい
るか?
相関チェック
● 2つ以上の項目にまたがるチェック● 例
○ 性別で男性を選択しているのに、妊婦の項目にチェック
していないか?
コード例
コード例
以下のようなフィールドを持つUserFormがあるとする
● 名前(name)● 性別(sex)● 妊娠しているか(pregnant)
コード例 単項目チェック
@NotNull(message = "性別がぬるぽ")private Sex sex;
コード例 単項目チェック
● フィールドまたはそのgetterにConstraintsを付与
コード例 相関チェック
@AssertTrue(message = "男性なのに妊娠してるって言ってる。。")public boolean isValidPregnant() {
// 性別が入力されていない時は、そちらで引っかかるのでバリデーショ
ンしない
if (sex == null) {return true;
}// 妊娠していると選択している人が女性であることをチェック
if (pregnant) {return Sex.FEMALE == sex;
} return true;
}
コード例 相関チェック
● メソッドを定義してそこにアノテーションを付与● 個人的には@AssertTrueのみ利用すれば良い
と思う○ Bean ValidationのValidatorのお作法的に、isValidでバ
リデーションOKならばtrueを返すようになっている。その
流れに沿った方が分かりやすい
コード例 単体テスト(特定プロパティのみのバリデーション)
private Validator validator =Validation.buildDefaultValidatorFactory().getValidator();
@Testpublic void validateName_正常系() {
UserForm userForm = new UserForm();
userForm.setName("eiryu");Set<ConstraintViolation<UserForm>> violations =
validator.validateProperty(userForm, "name");LOGGER.info("violations: " + violations);
assertThat(violations, hasSize(0));}
コード例 単体テスト(JavaBeans全体のバリデーション)
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
@Testpublic void validate_正常系() {
UserForm userForm = new UserForm();userForm.setName("eiryu");userForm.setSex(Sex.MALE);userForm.setPregnant(false);
Set<ConstraintViolation<UserForm>> violations =validator.validate(userForm);
LOGGER.info("violations: " + violations);
assertThat(violations, hasSize(0));}
コード例 Webアプリケーション(Spring Bootのコントローラ)
@RequestMapping("registor")public String registor(
@Valid UserForm userForm, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {LOGGER.warn("bindingResult: " + bindingResult);return "index";
}// some process..
return "redirect:/complete";}
気にすべきポイント・TIPS
気にすべきポイント・TIPS(バリデーションの順番)
● 普通に使うと、バリデーションが行われる順番はランダム
○ Webアプリケーションでメッセージを上部に列挙するよう
な場合に注意
○ 相関チェックでは、関係するフィールドが単項目チェック
済みでないことに注意して実装する必要がある
気にすべきポイント・TIPS(バリデーションの順番)
● Group、 Group sequence という仕組みを使うとバリデーションの順番を制御することが出来る
○ JSRのSpecの例では、バリデーションで非常に重い処
理があって、それは他のバリデーションがOKだった時の
み実行する、というもの
○ 他に想定出来るのは、同時に2つ以上エラーになってい
るのに1つずつエラーメッセージ出すとか?
気にすべきポイント・TIPS(メッセージ)
メッセージはプロパティファイルに外だし可能。ロケールごとのファイルを用意すればi18n対応も可能
● ValidationMessages.properties● ValidationMessages_ja_JP.properties
プロパティファイルのエンコーディングはISO-8859-1で作成すること(昭和か!)
● IDEの自動変換かnative2ascii(昭和か!)で頑張りましょう
@NotNull(message = "{NotNull.sex}")private Sex sex;
気にすべきポイント・TIPS(その他)
● JavaBeansの中にJavaBeansがあるようなケースでは、そのフィールドに対して@Validアノテーションを付与すれば再帰的にバリデーションされる
public class UserForm {...
@Validprivate Address address;
...}
ご清聴ありがとうございました
参考文献
● http://beanvalidation.org/● http://yamkazu.hatenablog.
com/entry/20110206/1296985545