SpringBoot で Validation 使った時のの簡易メモ
良いやり方は模索中。。。
実行環境
- Windows11
- Pleiades 2024 Full Edition
- Maven v3.9.6
- SpringFramework Boot v3.3.0
- Java v21
- spring-boot-starter-thymeleaf
- spring-boot-starter-web
- spring-boot-starter-validation
プロジェクト作成
- Spring Boot DevTools
- Spring Web
- Lombok
- Thymeleaf
- Validation
Validation で追加された依存関係は以下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
バリデーションするDTO作成
入力フォームで使う変数を持ったオブジェクト
クラス変数にバリデーションをアノテーションで追加
@Data
@AllArgsConstructor
@NoArgsConstructor
public class XxxDto {
@NotNull
private Integer val1;
@NotBlank
private String val2;
}
コントローラでバリデーション適用
コントローラの引数にアノテーション @Validated
とバリデーション結果をとれる BindingResult
を追加する
引数の順番は必ず @Validated
つけたやつの後に BindingResult
にする
この順番以外だとエラーになるので注意!
@PostMapping("/url_samp")
public String sample(Model model, @Validated @ModelAttribute XxxDto dto, BindingResult result) {
// バリデーション確認
if (result.hasErrors()) {
// とりあえずエラー内容出力
result.getFieldErrors().forEach(e -> System.out.println(e.getField() + ":" + e.getDefaultMessage()));
// 結果を画面に設定
model.addAttribute("errorResult", result);
return "sampl";
}
// バリデーションOKの時の処理
// ・
// ・
return "sampl";
}
html でエラー内容表示
一旦、簡易にバリデーション結果から直接、エラー項目とメッセージを取得して表示
<div th:if="${errorResult}">
<li th:each="err : ${errorResult.fieldErrors}" th:text="${err.field + ':' + err.defaultMessage}"></li>
</div>
メッセージを変える
メッセージプロパティの元は hibernate-validator
に置いてある
上書きだったり新しいバリデータ作るときは resources
の直下に以下のファイルを作る
上書きのときは元々のキーと合わせる必要あり
- ValidationMessages.properties
- ValidationMessages_ja.properties
jakarta.validation.constraints.NotBlank.message = ないよ。。。blank
jakarta.validation.constraints.NotNull.message = ないよ。。。null
独自でバリデーションつくる
標準にはない独自バリデーションが作れる、DBへのチェックなども作れる
クラスは以下の2つを作る
使いたいときは作ったアノテーションクラスをクラス or クラス変数 or 引数に追加するだけであとは標準と同じ!
- アノテーションクラス(クラス、クラス変数、引数につけるアノテーション)
- バリデーションクラス(チェック行うクラス)
あとメッセージの追加を忘れずに
- ValidationMessages.properties
- ValidationMessages_ja.properties
package com.example.demo.validator;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
// バリデーションクラスを設定
@Constraint(validatedBy = SampleValueValidator.class)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface SampleValue {
// メッセージプロパティに設定するキーを使う
String message() default "{sample.value.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
package com.example.demo.validator;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
// ConstraintValidator<アノテーションクラス設定, バリデーションする型設定> の実態クラスにする
public class SampleValueValidator implements ConstraintValidator<SampleValue, String> {
// バリデーションの実装, バリデーションエラーの時は false を返す
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return "Sample".equals(value);
}
}
sample.value.message = Let's make it Sample
sample.value.message = Sample にしましょう
バリデーションの実行制御(コントローラごとに分けるパターン)
入力フォームで使うオブジェクトのクラス変数に追加したバリデーションでアクションごとに実行制御できる
実行制御するときはアノテーションクラスの groups
を使う
入力フォームで使うオブジェクトのクラス変数のアノテーションのところに groups={ クラス... }
を設定
コントローラの引数のアノテーションのところに @Validated({ クラス... })
を設定
クラスを合わせる必要がある(クラス自体は作っても良いし、すでにあるやつでもOK、アクションを制御できる感じのやつを使う)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class XxxDto {
// groups = { クラス... } ここに設定したクラスをコントローラ側で設定するとバリデーション実行
@NotNull(groups = { ClasA.class })
private Integer val1;
@NotBlank
private String val2;
}
// Validated({クラス...}) 上のオブジェクトで設定したクラスを設定
// Default.class を設定しておくと groups の設定がないバリデーションも実行できる
// Validated でクラスを設定しない時は Default.class を設定してることになる
@PostMapping("/url_samp")
public String sample(Model model, @Validated({ Default.class, ClasA.class }) @ModelAttribute XxxDto dto, BindingResult result) {
// バリデーション確認
if (result.hasErrors()) {
// とりあえずエラー内容出力
result.getFieldErrors().forEach(e -> System.out.println(e.getField() + ":" + e.getDefaultMessage()));
// 結果を画面に設定
model.addAttribute("errorResult", result);
return "sampl";
}
// バリデーションOKの時の処理
// ・
// ・
return "sampl";
}