LoginSignup
1
1

More than 5 years have passed since last update.

いずれか1つのフィールドへの入力だけを許可するバリデータの作り方

Posted at

はじめに

ぶっちゃけBean Validationの拡張方法です:thermometer_face:

確認環境

  • 開発環境
    • JDK 1.8
    • Spring Framework 4.3
    • BeanValidation 1.1
  • 動作環境
    • JBoss EAP 7.1

※フレームワークとしてTERASOLUNA Server Framework for Java (5.3.0.RELEASE)を使用しています。

そもそもバリデータを作るには?

まずはアノテーションを作る

ほとんどConstraint compositionにあるコードのコピペですが:sweat:

AllowSingleInput.java
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = {AllowSingleInputValidator.class}) // ↓で作るクラス
@Target({TYPE, ANNOTATION_TYPE}) // クラスまたはアノテーションにのみ付加できるようにする
@Retention(RUNTIME)
public @interface AllowSingleInput {
  String message() default "{com.neriudon.example.validator.SingleInput.message}";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

  String[] fields(); // 配列にする

  @Target({TYPE, ANNOTATION_TYPE})
  @Retention(RUNTIME)
  @Documented
  @interface List {
    AllowSingleInput[] value();
  }
}

ポイントはアノテーションのターゲットをクラスまたはアノテーションのみにすることと、Stringの配列をフィールドに持たせることです。
メッセージはべた書きしてもいいのですが、プロパティでPlease input to only one text filedを設定しています。

バリデータを作る

さて、実際の入力チェックをするクラスを作ります。
まぁ基本はExampleのコピペなのですが:sweat:

AllowSingleInputValidator.java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.StringUtils;

public class AllowSingleInputValidator implements ConstraintValidator<AllowSingleInput, Object> {
  private String[] fields;

  private String message;

  @Override
  public void initialize(AllowSingleInput constraintAnnotation) {
    fields = constraintAnnotation.fields(); // フィールド名を取得
    message = constraintAnnotation.message();
  }

  @Override
  public boolean isValid(Object value, ConstraintValidatorContext context) {
    BeanWrapper beanWrapper = new BeanWrapperImpl(value);
    // いずれか1つのフィールドに入力されたかチェックする処理
    boolean isSingleInput = false;
    for (String field : fields) {
      if (!StringUtils.isEmpty(beanWrapper.getPropertyValue(field))) {
        if (isSingleInput) {
          isSingleInput = false;
          break;
        } else {
          isSingleInput = true;
        }
      }
    }

    if (isSingleInput) {
      return true;
    } else {
      context.disableDefaultConstraintViolation();
      // 条件を満たさない場合はメッセージ出力
      context.buildConstraintViolationWithTemplate(message).addPropertyNode(fields[0])
          .addConstraintViolation();
      return false;
    }
  }
}

initializeで対象のフィールド名を取得し、isValidでいずれか1つのフィールドだけに入力されているかをチェックしています(もしかしたら他にいい書き方があるかも:frowning2:)。

使い方

Formクラスにアノテーションを付与し、fieldsに入力チェックをするフィールド名を設定します。

@AllowSingleInput(fields = {"todoTitle1", "todoTitle2", "todoTitle3"})
public class TodoForm implements Serializable {

  private static final long serialVersionUID = 1L;

  private String todoTitle1;

  private String todoTitle2;

  private String todoTitle3;

  // getter/setterは省略します
}

jspは特に変更する必要はありません。

<!-- Formのところだけ抜き出します -->
<form:form action="${pageContext.request.contextPath}/todo/create"
    method="post" modelAttribute="todoForm">
    <form:label path="todoTitle1"/>
    <form:input path="todoTitle1" />
    <form:errors path="todoTitle1" cssClass="text-error" /><br>
    <form:label path="todoTitle2"/>
    <form:input path="todoTitle2" />
    <form:errors path="todoTitle2" cssClass="text-error" /><br>
    <form:label path="todoTitle3"/>
    <form:input path="todoTitle3" />
    <form:errors path="todoTitle3" cssClass="text-error" /><br>
    <form:button>Create Todo</form:button>
</form:form>

実行結果

実行結果

複数のフィールドに入力してボタンを押すとエラーメッセージが表示されるようになりました:v:

この投稿に至った経緯

携わっている案件で、このバリデータが必要になったためメモとして。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1