SpringBoot Beanバリデーションの作成方法
アノテーションを自作して独自のBeanバリデーションを作成する方法
①アノテーションクラスの作成
【基本構文】
//アノテーションで付加された情報がどの段階まで保持されるかを定義
@Retention(リテンション名)
//アノテーションを付与できる対象を指定
@Target(ターゲット名)
// javadoc コマンドなどで作成したドキュメントに反映させる為の設定
@Documented
//バリデーションを行うクラスを指定
@Constraint(validatedBy = 実際にバリデーションを行うクラス名.class)
public @interface アノテーション名 {
//フィールドの設定(メソッドのようにカッコを付与 default値の設定が可能)
int maxLength() default 5;
・
・
//特定のバリデーショングループをカスタマイズ可能にする設定(※空の Class<?> 型で初期化)
Class<?>[] groups() default {};
//チェック対象のオブジェクトにメタ情報を与える為の宣言
Class<? extends Payload>[] payload() default {};
//エラー時に例外オブジェクトに設定されるメッセージ
String message() default "";
}
【Retentionアノテーションの種類】
・SOURCE
ソース上だけのアノテーションで、クラスファイルには記録されない
・CLASS
クラス・ファイルに記録され、実行時にVMによって保持されない
・RUNTIME
クラス・ファイルに記録、実行時にVMによって保持され、リフレクション可能
【Targetアノテーションの種類】
・ElementType.TYPE
クラス・インタフェース・enum・アノテーションの宣言
・ElementType.FIELD
フィールドの宣言(enum定数を含む)
・ElementType.METHOD
メソッドの宣言
・ElementType.PARAMETER
メソッドのパラメータの宣言
・ElementType.CONSTRUCTOR
コンストラクタの宣言
・ElementType.LOCAL_VALIABLE
ローカル変数の宣言
・ElementType.ANNOTATION_TYPE
アノテーション型の宣言
・ElementType.PACKAGE
パッケージの宣言
②バリデーションクラスの作成
【基本構文】
//ConstraintValidatorインターフェースを実装
public class バリデーションクラス名 implements ConstraintValidator<Sample, Object>{
フィールド名
・
・
/** アノテーションの情報を受け取る */
@Override
public void initialize(アノテーション名 constraintAnnotation) {
フィールド名 = constraintAnnotation.フィールド名;
・
・
message = constraintAnnotation.message();
}
@Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
// Beanバリデーションの検証処理を実装
//エラーの場合はfalseを返す
return false;
}
}
【ConstraintValidatorインターフェース】
ConstraintValidator<アノテーションクラス, バリデーション対象の型>を指定する
バリデーション対象の型はString型などを指定すれば良い
FormやDTO全体にバリデーションをかける場合はObject型を指定する
③実装サンプル
・アノテーションクラス
package com.example.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import com.example.logic.SampleValidationLogic;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
//尚、複数の場合は波括弧で括る
//@Target({
// ElementType.FIELD,
// ElementType.METHOD
//})
@Documented
@Constraint(validatedBy = SampleValidationLogic.class)
public @interface Sample {
int maxLength() default 5;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "";
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
//アノテーションを使用するときに、そのフィールド名を省略してパラメータを渡せるようにしておく
//単一値アノテーションで値のキー名が value の場合のみ、キー名を省略できる
ByteValidation[] value();
}
}
・実際にバリデーションを行うクラス
package com.example.logic;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import com.example.annotation.Sample;
public class SampleValidationLogic implements ConstraintValidator<Sample, Object>{
private int maxLength;
private String message;
/** アノテーションの情報を受け取る */
@Override
public void initialize(Sample constraintAnnotation) {
maxLength = constraintAnnotation.maxLength();
message = constraintAnnotation.message();
}
/** Beanバリデーションの検証処理 */
@Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
//Beanをラップ
BeanWrapper wrapper = new BeanWrapperImpl(obj);
//ラップされたBeanのインスタンスを取得
Object subObj = wrapper.getWrappedInstance();
int value = (int)(subObj);
//5文字より大きければエラーとする
if (value > maxLength) {
message = "error";
return false;
}
return true;
}
}
・アノテーションを付与するクラス
package com.example.domain;
import com.example.annotation.Sample;
public class SampleEntity {
//自作のSampleアノテーションを付与
//サンプルとして数値を10で初期化
@Sample
public int len = 10;
}
・コントローラークラス
package com.example.controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.domain.SampleEntity;
@RestController
public class SampleController {
@GetMapping
//@Validatedでバリデーションチェックし、BindingResultでエラーを受ける
String index(@Validated SampleEntity sampleEntity, BindingResult result) {
if (result.hasErrors()) {
return "error";
}
return "success";
}
}