Spring MVCというか、JSR-303で値の比較を行うヴァリデーション
ユーザ登録における、[パスワード]と[パスワードの再確認]欄の一致とかに使うやつを自分で用意する方法について(・ω・)
実装
アノテーションと実装はこんな感じのものを用意。
@Target({ TYPE, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = FieldCompareValidator.class) @Documented public @interface FieldCompare { String message() default "{smart.extension.spring.validator.FieldCompare.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String field(); String compareTo(); @Target({ TYPE, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented @interface List { FieldCompare[] value(); } }
public class FieldCompareValidator implements ConstraintValidator<FieldCompare, Object> { private String fieldFieldName; private String compareToFieldName; @Override public void initialize(final FieldCompare constraintAnnotation) { this.fieldFieldName = constraintAnnotation.field(); this.compareToFieldName = constraintAnnotation.compareTo(); } @Override public boolean isValid(final Object value, final ConstraintValidatorContext context) { final BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(value); final Object fieldValue = wrapper.getPropertyValue(this.fieldFieldName); final Object compareToValue = wrapper.getPropertyValue(this.compareToFieldName); boolean isValid = ((fieldValue == null) && (compareToValue == null)) || ((fieldValue != null) && (fieldValue.equals(compareToValue))); if (!isValid) { context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addNode(this.fieldFieldName).addConstraintViolation() .disableDefaultConstraintViolation(); } return isValid; } }
サンプル
例えば検証対象のモデルに下記の様な感じで設定。
@FieldCompare(field = "newPasswordConfirm", compareTo = "newPassword") public class PasswordViewModel implements Serializable { @NotEmpty private String newPassword; private String newPasswordConfirm; ... }
<ul> <li> <form:password path="newPassword"/> <form:errors path="newPassword" cssClass="error" /> </li> <li> <form:password path="newPasswordConfirm"/> <form:errors path="newPasswordConfirm" cssClass="error" /> </li> </ul>
ポイントは、入力欄のエラーとして扱う方のメンバをfieldで指定すること。
この場合、パスワードが一致しなかった時のエラーはnewPasswordConfirmの方に表示されます。
FieldCompareValidatorのcontext.buildConstraintViolationWithTemplate()のあたりでやっているのがこの設定です(・ω・)
これ、どっかのサイトを参考にしたものですが、出典は忘れました(・∀・;)