【Spring MVC】フォームの入力チェック方法(相関チェックルールの追加)

概要

Spring MVCにてフォームの入力チェックを行う方法についてまとめた。
今回は相関チェックルールを作成する方法について紹介する。

 

前提

入力チェックに必要な情報は以下となる。

メッセージプロパティ定義

概要 Springのメッセージ管理を行うMessageSourceを使用して外部ファイルからメッセージを取得する方法についてまとめた。 MessageSourceはプロパティファイルに定義したメッセージを取得する機能を提供する。 […]

【Spring MVC】MessageSourceを使用する方法
入力チェックに必要な資材

概要 Spring MVCにてフォームの入力チェックを行うための準備と入力チェックの全体像についてまとめた。 入力チェックにはBean Validationを使用する。 Bean Validationの機能を使用するためには、その実装[…]

【Spring MVC】フォームの入力チェック方法(準備)
アノテーションの基本的な使い方

概要 Spring MVCにてフォームの入力チェックを行う方法についてまとめた。 入力チェックには、フォームのフィールドに入力チェック用のアノテーションを付与する。 今回は基礎的なBean Validationと、その実装であるH[…]

【Spring MVC】フォームの入力チェック方法(基本な使い方)
アノテーションクラスの作成方法

概要 Spring MVCにてフォームの入力チェックを行う方法についてまとめた。 今回は独自の単項目入力チェックルールを作成する方法について紹介する。   前提 入力チェックに必要な情報は以下となる。 [sit[…]

【Spring MVC】フォームの入力チェック方法(独自単項目チェックルールの追加)

 

相関チェックルールの追加

2つの入力項目にて同じ内容が入力されていることを確認するための独自アノテーションを作成する。

相関チェックを作成するために必要なクラスは以下となる。

①独自アノテーションクラス
②上記の具体的なバリデーションロジックを提供するクラス

 

独自アノテーションクラス

相関チェックを行うための独自アノテーションクラスの例は以下となる。

FieldsMatch.java


package com.example.prototype.web.common.validation;			
			
import static java.lang.annotation.ElementType.*;			
import static java.lang.annotation.RetentionPolicy.*;			
			
import java.lang.annotation.Documented;			
import java.lang.annotation.Retention;			
import java.lang.annotation.Target;			
			
import javax.validation.Constraint;			
import javax.validation.Payload;			
			
/**			
 * 相関チェック用のアノテーションクラス.<br>			
 * 			
 */			
@Documented			
@Constraint(validatedBy = { FieldsMatchValidator.class }) // ①			
@Retention(RUNTIME)			
@Target({ TYPE, ANNOTATION_TYPE })			
public @interface FieldsMatch {			
	String message() default "{FieldsMatch.default.message}"; // ②		
			
	Class<?>[] groups() default {};		
			
	Class<? extends Payload>[] payload() default {};		
			
	/** チェック対象 */		
	String property(); // ③		
			
	/** 比較対象 */		
	String comparingProperty(); // ③		
}			

 

@Constraint(validatedBy = { FieldsMatchValidator.class }) // ①

@Constraintアノテーションに、当アノテーションの具体的なバリデーションロジッククラス(後ほど紹介)を指定する。

 

String message() default “{FieldsMatch.default.message}”; // ②

上記はメッセージプロパティのエラーメッセージキーを指定している。
何もしなければエラー時は上記のメッセージキーに紐づくメッセージ内容が表示される。

 

/** チェック対象 */
String property(); // ③
/** 比較対象 */
String comparingProperty(); // ③

相関チェックを行うための2つのフィールドを定義する。

 

バリデーションロジッククラス

具体的な入力チェックを行うクラスを作成する。

FieldsMatchValidator.java


package com.example.prototype.web.common.validation;					
					
import javax.validation.ConstraintValidator;					
import javax.validation.ConstraintValidatorContext;					
					
import org.springframework.beans.BeanWrapperImpl;					
import org.springframework.util.ObjectUtils;					
					
/**					
 * 相関チェック用のバリデーションロジッククラス.<br>					
 * 					
 */					
public class FieldsMatchValidator implements ConstraintValidator<FieldsMatch, Object> { // ①					
	/** チェック対象 */				
	private String property;				
	/** 比較対象 */				
	private String comparingProperty;				
					
	@Override				
	public void initialize(FieldsMatch constraintAnnotation) {				
		// フィールド名の初期化 ②			
		this.property = constraintAnnotation.property();			
		this.comparingProperty = constraintAnnotation.comparingProperty();			
	}				
					
	@Override				
	public boolean isValid(Object value, ConstraintValidatorContext context) {				
		// フィールドの値を取得 // ③			
		var beanWrapper = new BeanWrapperImpl(value);			
		Object propertyValue = beanWrapper.getPropertyValue(property);			
		Object complaringPropertyValue = beanWrapper.getPropertyValue(comparingProperty);			
		// プロパティの比較 // ④			
		boolean res = ObjectUtils.nullSafeEquals(propertyValue, complaringPropertyValue);			
					
		// チェック結果判定 ⑤			
		if (!res) {			
			// デフォルトのメッセージを使用する場合		
			context.buildConstraintViolationWithTemplate(		
					context.getDefaultConstraintMessageTemplate()).addPropertyNode(property)
					.addConstraintViolation();
		}			
					
		return res;			
	}				
}					

 

public class FieldsMatchValidator implements ConstraintValidator<FieldsMatch, Object> { // ①

ConstraintValidatorインターフェースを実装し、以下のメソッドをオーバーライドする。

・initialize: フィールドの初期化などに使用する
・isValid: 入力値検証を行う

 

// フィールドの初期化 ②
this.property = constraintAnnotation.property();
this.comparingProperty = constraintAnnotation.comparingProperty();

相関チェックを行う2つのフィールド名をセットする。

 

// フィールドの値を取得 // ③
var beanWrapper = new BeanWrapperImpl(value);
Object propertyValue = beanWrapper.getPropertyValue(property);
Object complaringPropertyValue = beanWrapper.getPropertyValue(comparingProperty);

Springの提供するBeanWrapperImplを使用して、value(フォームオブジェクト)をラップしたオブジェクトを作成する。

BeanWrapperImplにフィールド名を渡すことで、フォームに格納された値を取得できる。
上記ではpropertyとcomparingPropertyに指定したフィールドの値を取得している。

 

// プロパティの比較 // ④
boolean res = ObjectUtils.nullSafeEquals(propertyValue, complaringPropertyValue);

ObjectUtils.nullSafeEqualsメソッドを使用して、2つのフィールドの値を比較している。
上記メソッドはnull値でも安全に比較できる

2つのフィールドが等しい場合はtrueを、等しくない場合はfalseを返却する。

 

// チェック結果判定 ⑤
if (!res) {

上記のブロックでは入力チェックエラー時のエラーメッセージの挙動について実装している。
デフォルトのエラーメッセージ(messageフィールド)を使用するか、
デフォルト以外のカスタムメッセージを使用するかで実装方法が異なる。

 

 デフォルトのエラーメッセージを使用

デフォルトのエラーメッセージを使用する場合、以下のように実装する。

FieldsMatchValidator.java


// デフォルトのメッセージを使用する場合		
context.buildConstraintViolationWithTemplate(		
		context.getDefaultConstraintMessageTemplate()).addPropertyNode(property)
		.addConstraintViolation();

 

context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
上記はデフォルトのエラーメッセージを使用するということ。
.addPropertyNode(property)
上記はどのフィールドにエラーメッセージを表示するかということ。
.addConstraintViolation();

上記はエラーメッセージ表示に必要。

 

カスタムエラーメッセージを使用

デフォルトエラーメッセージではなく、独自のエラーメッセージを使用したい場合は以下のように実装する。

FieldsMatchValidator.java


// カスタムメッセージを使用する場合			
context.disableDefaultConstraintViolation();			
context.buildConstraintViolationWithTemplate("{FieldsMatch.custom.message}")			
		.addPropertyNode(property).addConstraintViolation();	

 

context.disableDefaultConstraintViolation();

上記はデフォルトのエラーメッセージを表示しないようにする設定。
※実装しないとデフォルトのエラーとカスタムのエラーどちらも表示されてしまう

 

context.buildConstraintViolationWithTemplate(“{FieldsMatch.custom.message}”)

上記はデフォルトで定義しているエラーメッセージではなく、”{FieldsMatch.custom.message}”というエラーメッセージキーを定義している。

 

使用方法

作成した独自アノテーションを使用する。
今回は「パスワード」と「パスワード(確認用)」フィールドを用いて、どちらも同じ値であることを確認する。

 

FooForm.java


@Data		
@FieldsMatch(property = "password", comparingProperty = "confirmPassword") // ①		
public class FooForm implements Serializable {		
	// フォーム部品を追加していく	
	// パスワード	
	@Alphanumeric	
	private String password;	
	// 確認用パスワード	
	private String confirmPassword;	
		
}		

 

@FieldsMatch(property = “password”, comparingProperty = “confirmPassword”) // ①

作成した相関チェックアノテーションはクラスに付与する。
propertyとcomparingProperty属性に相関チェックを適用したいフィールドを指定する。

 

メッセージプロパティには以下のように定義する。

messages_ja.properties


fooForm.password=パスワード
fooForm.confirmPassword=パスワード(確認用)
FieldsMatch.default.message={0}と{1}の値が一致しません。

 

エラーの結果は以下となった。

【Spring MVC_フォームの入力チェック方法(相関チェックルールの追加)】チェック結果1
▲フィールド名が正しくバインドされなかった

 

メッセージプロパティに定義したプレースフォルダに、正しくバインドされない事象が起きた。
2つめのプロパティ名は「フォーム名.フィールド名」という記載で定義すると、正しく適用されない模様。

 

以下のようにメッセージ定義を修正した。

messages_ja.properties


fooForm.password=パスワード
confirmPassword=パスワード(確認用)
FieldsMatch.default.message={0}と{1}の値が一致しません。

 

実行結果

【Spring MVC_フォームの入力チェック方法(相関チェックルールの追加)】チェック結果2
▲フィールド名が正しくバインドされた

 

スポンサーリンク