Java/Spring Bootのバリデーション設定
(昔かいた記事が公開されていなかったので、アウトプットしておきます)
Spring Bootアプリケーションでのバリデーションの設定方法についてまとめます。
なお、Spring Bootでバリデーションを有効にするにはbuild.gradle
もしくはpom.xml
でspring-boot-starter-validationを追加しておく必要があります。
アノテーションの紹介
バリデーションを有効にするために使うアノテーションは@Valid
と@Validated
の2つです。
@Valid
はJava標準(Bean Validation)で用意されたアノテーションです。
@Validated
は@Valid
を拡張されたものでSpring Framework側で用意されたアノテーションになります。
@Validated
アノテーションの方がより高度なバリデーションをすることが可能です。
どちらを使うかは要件次第になりますが、この記事では@Valid
を使用します。
その他、今回利用するアノテーションを紹介します。
@NotBlank : 文字列がnullではなく、空文字ではないことを検証
@NotNull : nullでないことを検証
@Pattern : 文字列が正規表現にマッチすることを検証
@Size : 文字数または配列の要素数が範囲内であることを検証
セミナー参加申し込みフォームを使ったサンプル
今回はセミナーへの参加申し込みフォームのバリデーションをかけることにします。
フォームへはセミナーのID、名前、メールアドレス、電話番号、参加希望日を指定して、フォーム送信するというイメージです。
{
"eventId": "2194181-1a",
"name": "my name",
"mail": "mail@xxxx.com",
"telephoneNumber": "00011112222"
}
まずは、セミナーの申し込みをするAPIを作成し、バリデーションを有効にするため@Valid
アノテーションをRequestクラスへ付与しています。
ここで@Valid
が抜けていると、Requestクラスのフィールドにバリデーションをつけても機能しないので、要注意です。
Requestクラスはこれら(セミナーのID、名前、メールアドレス、電話番号)の情報を持ちます。
@ReastController
public class SeminarController{
// 一部省略
/**
* セミナーへの参加申し込み用API
*/
@PostMapping("/entry")
public Response entrySeminar(@RequestBody @Valid Request request){
return seminar.service(request);
}
}
それでは、Requestクラスへバリデーションを付与します。
Requestクラスが持つ全てのフィールドはセミナーの申し込みには必須の事項になります。
そのため、全てのフィールドに@NotNull
を付与します。
Requestクラスの呼び出しもとのSeminarControllerで@Valid
を付与しているので、この時点で@NotNull
バリデーションが機能します。
class Request {
@NotNull
EventId eventId;
@NotNull
Name name;
@NotNull
Mail mail;
@NotNull
TelephoneNumber telephoneNumber;
Request(EventId eventId,Name name, Mail mail, TelephoneNumber telephoneNumber) {
this.eventId = eventId;
this.name = name;
this.mail = mail;
this.telephoneNumber = telephoneNumber;
}
}
では、次に各フィールドに対するバリデーションをかけてみます。
まずは各フィールドに@Valid
アノテーションを付与します。前述の通り@Valid
を忘れると各クラスで付与したバリデーションが機能しないので注意しましょう。
アノテーションの数が増えてきたので、コードが見辛くなってきましたが、一旦このまま進めます。
class Request {
@NotNull
@Valid
EventId eventId;
@NotNull
@Valid
Name name;
@NotNull
@Valid
Mail mail;
@NotNull
@Valid
TelephoneNumber telephoneNumber;
Request(EventId eventId,Name name, Mail mail, TelephoneNumber telephoneNumber) {
this.eventId = eventId;
this.name = name;
this.mail = mail;
this.telephoneNumber = telephoneNumber;
}
}
EventIdは空文字でないことを検証するバリデーションを付与します。これだけでRequest時のバリデーションが機能します。
class EventId {
@NotEmpty
int value;
EventId(String value) {
this.value = value;
}
String getValue() {
return value;
}
}
nameも同様に空文字でないことの検証のみにします。
class Name {
@NotEmpty
String value;
Name(String value) {
this.value = value;
}
String getValue() {
return value;
}
}
基本的にはバリデーションの有効化自体は、2ステップでここまでで設定方法の流れがつかめてきたと思います。
- バリデーションしたいクラスの呼び出し元で
@Valid
アノテーションを付与する - バリデーションしたいクラスのフィールドに対して検証したいアノテーションを付与する
では、続いてMailとTelephoneNumberのバリデーションをかけてみます。
Mailのバリデーションをかけていきましょう。
メールアドレスを検証するバリデーションは正規表現でマッチするかを確認することにします。
class Mail {
@Pattern(regex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")
String value;
Mail(String value) {
this.value = value;
}
String getValue() {
return value;
}
}
TelephoneNumberのバリデーションをかけます。これで最後です。
電話番号は桁数のチェックするという仕様にします。TelephoneNumberのvalueはString型であるため@Size
アノテーションを使用します。
なお、型によって有効にできるアノテーションは異なるため、アノテーションが機能する型が何かは都度調べる必要があります。
class TelephoneNumber {
@Size(min=10,max=11)
String value;
public TelephoneNumber(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
バリデーションの基礎的な例はこれで抑えられたはずです。
バリデーション関連のアノテーションは他にもたくさんあるので、用途に応じて調べて有効にすると良いと思います。
参考 - バリデーションエラー発生時のメッセージ表示方法
バリデーションエラーが発生した時に、個別にメッセージを表示したい場合の対応を紹介します。
@NotBlank(message = "不正な入力値です。")
のようにアノテーションの引数へ指定すればメッセージを表示させることができます。
ただし、毎度同じアノテーションに対して文字列を指定するのは手間ですし、変更漏れが生じやすくなってしまいます。
例えば@NotBlank
のエラー発生時に表示するメッセージが同じであれば、propertiesファイルに文字を定義してあげると良いです。
message.propertiesを作成し、ファイル内に以下のようにメッセージを定義します。
invalid.input.message=不正な入力値です
アノテーション側ではpropertiesで定義された値を参照する形にすれば、変更箇所を減らすことができるのでおすすめです。
@NotBlank(message = ${invalid.input.message})
のように指定してあげることで使えます。
まとめ
この記事ではバリデーションを有効にするための設定とサンプルを提示しました。
なお、バリデーションのアノテーションは関連するクラスにつけなければいけないので、抜けがあった場合に実際に機能しているかどうかを確認しづらいという問題があります。
実際にリクエストを送ることで確認しても良いのですが、 追加するたびに実行させるのも面倒なので、バリデーションができていることを確認するテストを書いて確かめることがおすすめです。
Discussion