LoginSignup
0
0

More than 1 year has passed since last update.

【Spring Boot】自作のバリデーションを作る

Last updated at Posted at 2022-08-23

バリデーションを自作する方法を学んだので、備忘として本記事を作成しました。

使用環境

  • Windows10 (64bit)
  • spring-boot : 2.7.1
  • postgres : 11.15

ユースケース

ユーザーを新規会員登録させるときに、emailとpasswordの入力が必須。
その際に既に登録してあるemailで新規会員登録できないようにしたいので、
入力されたemailが既にDBに登録があった場合はエラーとなるように、バリデーションを自作する。
バリデーションの名前は@UniqueEmailとする。

エンティティクラスの作成

今回、ユーザー情報はusersテーブルに格納しておくので、
そのテーブルに対応するuserクラスを作成する。

user.java
package com.example.domain;

import文省略

public class User {
	private int id;
	private String email;
	private String password;

    constructor,getter,setter 省略
}

リポジトリクラスの作成

emailが既に登録されているかどうかDBに問い合わせるリポジトリクラスUserRepository.javaを作成する。
今回は、Spring JDBCを用いてDBにアクセスする。

UserRepository.java
package com.example.repository;

import文省略

@Repository
public class UserRepository {
	
	@Autowired
	private NamedParameterJdbcTemplate template;
	
	private static final RowMapper<User> USER_ROW_MAPPER = (rs, i) ->{
		User user = new User();
		user.setId(rs.getInt("id"));
		user.setEmail(rs.getString("email"));
		user.setPassword(rs.getString("password"));	
		return user;
	};
	
	/**
	 * emailからユーザーを特定する
	 * @param email
	 * @return 
	 * 既に登録があった場合:emailを返却
	 * 登録がなかった場合:EmptyResultDataAccessExceptionをスロー
	 */
	public String findByEmail(String email) throws EmptyResultDataAccessException{
		String sql = "SELECT email FROM users WHERE email = :email";
		SqlParameterSource param = new MapSqlParameterSource().addValue("email", email);
		return template.queryForObject(sql, param, USER_ROW_MAPPER);
	}

UniqueEmailクラスを作成

本件の肝です。
今回、バリデーションの名前を@UniqueEmailにしたいので、UniqueEmailクラスを作成します。

✓ポイント

  • クラスの宣言に、@interface と付ける
  • クラスに下記アノテーションをつける
    • @Target : アノテーションが付与できる場所の指定を行う
    • @Retention:いつまでアノテーションを残すか設定する
    • @Constraint:バリデーションを実行するクラスを指定する
UniqueEmail.java
package com.example.validation;

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;

@Target({ ElementType.METHOD, ElementType.FIELD }) // アノテーションが付与できる場所の指定。今回は、メソッドとフィールドにアノテーションを付与できると指定。
@Retention(RetentionPolicy.RUNTIME) // いつまでアノテーションを残すか。この記述はRuntimeは実行時まで残すということ。
@Constraint(validatedBy = UniqueEmailValidator.class) // バリデーションを実行するクラスを指定。今回はUniqueEmailValidatorクラス で使用する。UniqueEmailValidatorクラスは後程実装する。
public @interface UniqueEmail { // クラスの宣言に、@interface と付ける

    // バリデーションが働いた時のエラーメッセージをここで指定する。
	String message() default "このEmailは既に使われています。別のメールアドレスを入力してください。";

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

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

バリデータークラスを作成

本件の肝2です。

✓ポイント

  • ConstraintValidatorインターフェイスをimplementsして、isValidメソッドを実装する
UniqueEmailValidator.java
package com.example.validation;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;

import com.example.repository.UserRepository;

// ConstraintValidator<A,T>インターフェイスをimplementsする。Aには先ほど作成したUniqueEmailクラスを指定する。
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String>{
	
	@Autowired
	private UserRepository userRepository;

    /**
	 * isValidメソッドを実装し、このなかでバリデーションエラー判定を行う
	 * @return 
	 * emailに重複がなかった場合:true
	 * emailに重複があった場合:false
	 */
	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		try {
			userRepository.findByEmail(value);
			return false;
		} catch (Exception e) {
			return true;
		}
	}

}

フォームクラスを作成する

ユーザーからの入力値を受け取るフォームクラスUserFormを作成する。
先ほど作成した@UniqueEmailをここで使用する。

UserForm.java
package com.example.form;

import com.example.validation.UniqueEmail;

public class UserForm {
	
	@UniqueEmail // 自作のバリデーターを使えるようになる
	private String email;
	private String password;

    constructor,getter,setter 省略

}

終わりに

自作のバリデーターを使いたくなる場面は結構出てくるかと思うので、備忘のために執筆しました。
間違っている部分もあるかと思いますので、その際はご指摘頂ければと思います。

参考文献

【Spring Boot】バリデーション
Spring Frameworkで使用できるBean Validationアノテーション一覧

0
0
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
0
0