#author("2020-06-30T09:30:45+00:00","","")
[[SpringBoot]]

* Spring Boot でバリデーションする [#gcd475fa]

2020-05-20 中村

Spring Bootでデータのバリデーション(検査)を行う方法をまとめる

** バリデーション (Validation) とは [#e73b4db9]

@Viewクラス(Webページ)のフォームから送られてくる値や
APIを呼び出す際の引数の型や値を検査して,不正なデータが
あれば棄却するようにする仕組み.
バリデーションがないと,おかしなEntityがDBに保存されたり,
不正なAPI呼び出しを許したりする.これらのことは,
セキュリティホールにもつながる.

** バリデーションはどこでやるか? [#t5abcbc1]
[[HTML5ではバリデーション機能が仕様として追加された:https://www.atmarkit.co.jp/ait/articles/1104/25/news137.html]]ため
クライアント側(@View)でバリデーションすることも可能だが,APIを直接呼び出す場合などを考えればサーバ側でやるべき.
- もちろんクライアント側,サーバ側の両方でやれば万全だが.

[[Spring Bootの責務>SpringBoot/各レイヤの責務]]から考えると,
バリデーションはコントローラ層で行うことが望ましい.
まさに「水際ではじくべき」という考えに基づく.

** 準備 [#c300e52c]
''build.gradle'' のdependenciesに下記を追加

 //バリデーション用
 compile 'org.springframework.boot:spring-boot-starter-validation'
 

** 例題1 PitCoinのユーザ登録 [#j586af9a]

''UserForm.java'' -- フォーム用のBean
 @Data
 public class UserForm {
     /* ユーザID は 最大16文字.英数字,アンダーバー,ハイフンのみ許す */
     @Size(max = 16)
     @Pattern(regexp = "[0-9a-zA-Z_\\-]+")
     private String uid;
 
     /* 名前,パスワードは Null,空文字(""),空白のみでないことを検証*/
     @NotBlank
     private String name; 
 
     @NotBlank
     private String password;
     
     /* RFC2822に準拠したEmailアドレスかどうか検証する */
     @Email
     private String email;
 
 }


''PitCoinService.java'' -- コントローラ
 @RestController
 @Scope("request")
 @RequestMapping("/api")
 @Slf4j
 public class PitCoinService {
  :
  :
    @PostMapping("/users")
    public PitCoinResponse createUser(@RequestBody @Validated UserForm userForm) {
         // ↑ ユーザフォーム(DTO)をSpringの枠組みで検査する.
         // 検査失敗したらError Handlerで拾う
         String uid = userForm.getUid();
         log.info("Creating account " + uid);
         User user = um.createUser(userForm);
         return PitCoinResponse.createSuccessResponse(user, "User " + uid + " created.");
   }
  :

- 桁数@Size,正規表現@Pattern,空白チェック@NotBlank,メール形式@Email を検査する
- 具体的な検査内容はUserFormのコメントに書いてある通り.
- コントローラで呼び出す際,@Validatedのアノテーションをつける.失敗したら例外が投げられる.
- バリデーション違反が起こった際に投げられる例外の種類[[(参考):https://qiita.com/mitsuya/items/693d05b0121c88000cea]]
-- ①パスのパラメータ	ConstraintViolationException
-- ②引数で指定するケース	ConstraintViolationException
-- ③引数でDTOを指定するケース	BindException
-- ④引数で@RequestBodyをつけてDTOを指定するケース(JSON)	MethodArgumentNotValidException

** 例題2: 健康診断アプリの受診者追加 [#v88d0e9c]

''PersonForm.java'' --  フォーム用のBean
 @Data
 public class PersonForm {
 
    /* 名前は無記名は許さない */
     @NotBlank
     private String name;
 
     /* 誕生日はyyyy-mm-ddの形式 */
     @Pattern(regexp = "\\d{4}-\\d{2}-\\d{2}")
     private String birthday;
 
     /* 身長は0以上.整数部3桁,小数部4桁以内 */
     @Min(0)
     @Digits(integer = 3, fraction = 4)
     private Double height; // 身長
 
     /* 体重は0以上.整数部3桁,小数部4桁以内 */
     @Min(0)
     @Digits(integer = 3, fraction = 4)
     private Double weight; // 体重
 
 }

''PersonController.java'' -- コントローラ

 @RestController
 @Scope("request")
 @RequestMapping("/api")
 public class PersonController {
  :
      @PostMapping("/persons")
      public PersonDto addPerson(@RequestBody @Validated PersonForm form) {
          Person p = pm.addPerson(form.toEntity());
          return PersonDto.build(p);
      }
  :

** その他のアノテーション [#s91d76d7]
- [[TeraSolunaのページ:https://terasolunaorg.github.io/guideline/1.0.x/ja/ArchitectureInDetail/Validation.html#appendix]]

* 参考文献 [#ea0ecb75]

- Spring Boot アノテーション集
-- https://tosi-tech.net/2018/07/annotations-of-spring-boot/


- Spring 単項目バリデーションのテスト
-- https://qiita.com/kamikenta/items/da6f5f30d05f7abc1da4

- Spring BootでつくったAPIのリクエストのバリデーションで出るExceptionのまとめ
-- https://qiita.com/mitsuya/items/693d05b0121c88000cea

- SpringBootでフォームクラスのバリデーションテスト
-- https://qiita.com/TAKAHIRO-03/items/ebb7da1752e14a3b1d3d


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS