以下の内容について記載します
- メッセージファイルの利用について
- 単一項目チェック
- 複数項目チェック
事前準備
GitHub
https://github.com/jirentaicho/springbootsample
※メッセージの表示はコントローラーのアノテーションをRestControllerに変更します。
application.propertiesを
application.ymlとして、ymlファイルで記載を行う。
既存のpropertiesファイル
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/misaka
spring.datasource.username=misaka
spring.datasource.password=mikoto
ymlファイルに置き換えた例
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/misaka
username: misaka
password: mikoto
メッセージを表示する
参考
https://spring-boot-doma2-sample.readthedocs.io/ja/master/messages.html
- messages.properties
- ValidationMessages.properties
- PropertyNames.properties
このうちmessages.propertiesをsrc/main/resourcesに作成します。
anicom.message001=パーフェクトJava
anicom.message002={0}を取得しました。
application.ymlを修正します。
messagesのbasenameに拡張子を省いたファイル名を記載します。
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/misaka
username: misaka
password: mikoto
messages:
basename: messages
cache-duration: -1
encoding: UTF-8
設定したメッセージを利用してみます。
適当なコントローラーを作成してメッセージの取得ができるか確認してみます。
{0}のような埋め込みタイプは配列を渡して名称を指定します。
また、メッセージの作成にはMessageSourceを利用します。
@RestController
public class InitializeController {
@Autowired
private MessageSource messageSource;
@RequestMapping("message1")
public String getMessage1(Model model) {
String message = messageSource.getMessage("anicom.message001", null, Locale.JAPAN);
return message;
}
@RequestMapping("/message2")
public String getMessage2(Model model) {
String message = messageSource.getMessage("anicom.message002", new String[]{"御坂美琴"}, Locale.JAPAN);
return message;
}
}
バリデーション
参考
https://terasolunaorg.github.io/guideline/5.0.0.RELEASE/ja/ArchitectureInDetail/Validation.html
- 単一フィールド
- Bean Validation(javax.validation.constraints.NotEmptyを使う)
- 複数フィールド
- org.springframework.validation.Validatorインタフェースを実装したValidationクラス
単一フィールド
pomを修正します。spring-boot-starter-validationを追加します。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
コントローラーの引数になるFormクラス(ここではrequestにしています)に対してアノテーションを付与します。
今回はtitleに対してNotEmptyを付けました。
@Setter
@Getter
@NoArgsConstructor
public class AnimationRequest {
@NotEmpty
private String title;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date broadcast_start;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date broadcast_end;
}
コントローラーの修正
メソッドの引数に@Validatedアノテーションを付与します。BindingResultにバリデーション結果が入っています。
@Controller
public class RegisterController {
@Autowired
private AnimationService animationService;
@PostMapping("/register")
public String register(@Validated AnimationRequest request, BindingResult bindingResult , Model model) {
if(bindingResult.hasErrors()) {
System.out.println(bindingResult);
System.out.println("error");
return "redirect:/";
}
animationService.insert(request);
return "redirect:/";
}
}
メッセージの変更
Validationに関するメッセージは専用のプロパティファイルを作成します。
javax.validation.constraints.NotEmpty.message=タイトルは必須項目です。
apllication.ymlにも反映させます。
basenameにカンマ区切りでファイル名を追加します。
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/misaka
username: misaka
password: mikoto
messages:
basename: messages,ValidationMessages
cache-duration: -1
encoding: UTF-8
エラーを発生させると以下のようなメッセージがコンソールに吐かれます
Field error in object 'animationRequest' on field 'title': rejected value []; codes [NotEmpty.animationRequest.title,NotEmpty.title,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [animationRequest.title,title]; arguments []; default message [title]]; default message [タイトルは必須です。]
error
複数フィールド
少し手順が複雑です。以下のような手順になります。
- メッセージを登録する
- org.springframework.validation.Validatorを継承したクラスを作成する
- コントローラーにInitBinderアノテーションを利用して、WebDataBinderに継承したクラスを登録する
1は必須でないですが、せっかくメッセージをプロパティで管理しているので利用します。
とりあえず、放送開始日に入力があった場合は、放送終了日への入力を必須とするバリデーションを追加します。
メッセージを登録する
ValidationMessages.propertiesに以下のメッセージを追加します。
anicom.error.message001=放送開始日を入力した場合は、放送終了日の入力は必須です。
org.springframework.validation.Validatorを継承したクラスを作成する
実装すべきインターフェースのvalidateをObject型を引数に取ります。
わざわざexecuteメソッドを作る価値はないと思いますが、現状はAnimationValidationクラスなので作りましたが、色々と穴がある状態です(別のformが来たら多分例外発生します)
でも、動きは確認できます。
package com.volkruss.application.validation;
import java.util.Locale;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.volkruss.application.request.AnimationRequest;
@Component
public class AnimationValidation implements Validator{
@Autowired
private MessageSource messageSource;
@Override
public boolean supports(Class<?> clazz) {
// trueにしておく
return true;
}
@Override
public void validate(Object target, Errors errors) {
// 動作確認のため汚いですがキャストします。
execute((AnimationRequest)target,errors);
}
/**
* <P>
* 相関バリデーションを実行します。
* <br />
* 入力値の放送開始日付に入力がある場合は、放送終了日の入力が必須です。
* </P>
*
* @param request アニメーションリクエスト
* @param errors エラー
*/
private void execute(AnimationRequest request,Errors errors) {
// 放送開始日に入力があって、放送終了日に入力がない場合
if(Objects.nonNull(request.getBroadcast_start()) && Objects.isNull(request.getBroadcast_end()) ) {
errors.reject("broadcast_end_date",messageSource.getMessage("anicom.error.message001", null, Locale.JAPAN));
}
}
}
コントローラーにInitBinderアノテーションを利用して、WebDataBinderに継承したクラスを登録する
@InitBinderアノテーションを利用して、WebDataBinderに対して先ほど作成したAnimationValidationを登録します。
@Controller
public class RegisterController {
@Autowired
private AnimationService animationService;
@Autowired
private AnimationValidation animationValidation;
@InitBinder
public void validatorBinder(WebDataBinder binder) {
binder.addValidators(animationValidation);
}
@PostMapping("/register")
public String register(@Validated AnimationRequest request, BindingResult bindingResult , Model model) {
if(bindingResult.hasErrors()) {
System.out.println(bindingResult);
System.out.println("error");
return "redirect:/";
}
animationService.insert(request);
return "redirect:/";
}
}
これで。放送開始日にだけ入力を入れて登録すると、以下のようなログが出力されます。
org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'animationRequest' on field 'title': rejected value []; codes [NotEmpty.animationRequest.title,NotEmpty.title,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [animationRequest.title,title]; arguments []; default message [title]]; default message [タイトルは必須です。]
Error in object 'animationRequest': codes [broadcast_end_date.animationRequest,broadcast_end_date]; arguments []; default message [放送開始日を入力した場合は、放送終了日の入力は必須です。]
error