SpringBootで、@Component
内の関数の引数にバリデーションする方法を探したのでメモ
リクエストの内容をバリデーションするためにControllerクラスへの引数に @Valid
を付与してバリデーションを行う方法はよく見かけるが、実際のアプリケーションだとユースケース層の処理やドメインの処理への引数(=入出力としてではなくビジネスロジックとしての値)をバリデーションしたいことが多いはず(というのも、コントローラーに書くと入出力の数が増えるごとにバリデーションされる箇所が増えていくため)
前提として、spring-boot-starter-validation
が依存関係としてインストールされており以下のようなバリデーションの対象クラスと実行する関数を持つクラスが存在するとする。
// バリデーションの対象になるクラス
data class EmployeeForm(
@field:NotBlank // kotlinの場合、`field:`を付与しないとビルド時にフィールドのアノテーションと解釈されない
val name: String,
@field:Past // kotlinの場合、`field:`を付与しないとビルド時にフィールドのアノテーションと解釈されない
val dateOfBirth: LocalDate
)
// バリデーションを実行する関数を持つクラス
@Component
class HogehogeUsecase() {
fun registerEmployee(
employeeForm: EmployeeForm
) {
// ...
}
}
この場合HogehogeUsecase
にアノテーションを2つ加えるだけ。ただし該当のクラスがbeanとして登録されている必要がある
// バリデーションを実行する関数を持つクラス
@Component
+@Validated // 1. org.springframework.validation.annotation.Validated を付与
class HogehogeUsecase() {
fun registerEmployee(
+ @Valid employeeForm: EmployeeForm // 2. javax.validation.Valid を付与
- employeeForm: EmployeeForm
) {
// ...
}
}
これだけで引数に与えられた値がバリデートされ、もしエラーがなければ関数内の処理が実行される。もしエラーが1つでも存在すれば、 javax.validation.ConstraintViolationException
がthrowされる。
例えばエラーメッセージをhtml上に出すために整形したければ以下のように呼び出し元でcatchすることもできる
try {
hogehogeUsecase.registerEmployee(employeeForm)
} catch (e: ConstraintViolationException) {
val message = e.constraintViolations.joinToString("\n") {
it.message
}
}
もし引数がList<EmployeeForm>
というように複雑だった場合でもこの方法で対応可能。
参考にしたサイトなど↓