40
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SpringBoot + JPA + Thymeleafで簡単なCRUDを作る③~Validationの追加~

Last updated at Posted at 2017-10-25

内容

  • 前回の続き
  • SpringBootで簡単なCRUDアプリを作る
  • 今回は入力域にバリデーションをかける
    • 名前と年齢を必須項目にする
    • 年齢は0~150の範囲内にする
    • チーム名は20文字までにする
スクリーンショット 2017-10-25 22.49.22.png

手順

  1. entityにバリデーションの設定を追加する
  2. controllerにエラー制御を追加する
  3. templateにエラーメッセージを追加する

1. entityにバリデーションの設定を追加する

  • validationの設定はentityクラスの変数にアノテーションをつける
  • Player.javaを編集する
src/main/java/com/example/baseball/domain/Player.java
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @NotEmpty // ①
    private String name;
    @NotNull // ②
    @Min(value = 0) // ③
    @Max(value = 150)
    private Integer age;
    @Size(max = 20) // ④
    private String team;
    private String position;
  • ①:@NotEmptyをつけるとnullと空文字を許容しなくなる
  • ②:@NotNullをつけるとnullを許容しなくなる
  • ③:最小値は@Min最大値は@Maxで設定する
  • ④:文字数の制限は@Sizeをつける

2. controllerにエラー制御を追加する

  • エラーがあった場合にもとの画面に戻す処理を追加する
  • PlayerController.javaを修正する
src/main/java/com/example/baseball/controller/PlayerController.java
    @GetMapping("new")
    public String newPlayer(Model model) {
        // ①
        Player player = new Player();
        model.addAttribute("player", player);
        return "players/new";
    }

    @PostMapping
    public String create(@Valid @ModelAttribute Player player, BindingResult bindingResult) { // ②
        if(bindingResult.hasErrors()) return "players/new"; // ③
        playerService.save(player);
        return "redirect:/players";
    }

    @PutMapping("{id}")
    public String update(@PathVariable Long id, @Valid @ModelAttribute Player player, BindingResult bindingResult) {
        if(bindingResult.hasErrors()) return "players/edit";
        player.setId(id);
        playerService.save(player);
        return "redirect:/players";
    }
  • ①:新規作成画面に対してPlayerインスタンスを渡すようにする
    • これがないと入力エラー時に入力していた内容を保持することができない
  • ②:player@Validをつけることでvalidationチェック対象となる
    • アノテーションを横並びにしているが@Validplayerにかかっている
@Valid @ModelAttribute Player player
// ↑と↓は同じ
@Valid
@ModelAttribute
Player player
  • ②:エラーがあるとBindingResult bindingResultの中にエラーの情報がセットされる
  • ③:エラーがあるとbindingResult.hasErrors()がtrueを返すのでその場合はもとの画面に返している

3. templateにエラーメッセージを追加する

new.html

  • エラーがあってcontrollerに突き返された場合にエラーメッセージを表示するようにする
src/main/resources/templates/players/new.html
      <!-- ① -->
      <form th:action="@{/players}" th:method="post" th:object="${player}">
        <!-- ② -->
        <div class="form-group" th:classappend="${#fields.hasErrors('name')}? has-error">
          <label class="control-label">名前</label>
          <input class="form-control" type="text" th:field="*{name}" />
          <!-- ③ -->
          <span class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('age')}? has-error">
          <label class="control-label">年齢</label>
          <input class="form-control" type="number" th:field="*{age}" />
          <span class="text-danger" th:if="${#fields.hasErrors('age')}" th:errors="*{age}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('team')}? has-error">
          <label class="control-label">チーム名</label>
          <input class="form-control" type="text" th:field="*{team}" />
          <span class="text-danger" th:if="${#fields.hasErrors('team')}" th:errors="*{team}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('position')}? has-error">
          <label class="control-label">守備位置</label>
          <input class="form-control" type="text" th:field="*{position}" />
          <span class="text-danger" th:if="${#fields.hasErrors('position')}" th:errors="*{position}"></span>
        </div>
        <button class="btn btn-default" type="submit">作成</button>
      </form>
  • ①:controllerからplayerを受け取るようになったので、th:objectにセット
    • 各inputフィールドもth:fieldを使うように修正(ここの③参照)
    • なぜこの変更を入れたかというとエラーがあって突き返された時に、入力内容をvalueにセットし直したいから
  • ②:th:classappend="${#fields.hasErrors('name')}? has-error"の意味は、#fields.hasErrors('name')がtrueの時にclass属性にhas-errorを追加するよということ
    • #fieldsの中にエラーの情報が入っている
    • class属性にhas-errorをつけると、Bootstrapの定義によってラベルと枠が赤くなる
  • ③:エラーメッセージを表示するための領域
    • th:ifが設定された要素は、th:ifの値がtrueの時(ここで言うとエラーがあった時)のみ表示される
    • th:errors="*{name}"*{name}に対してセットされたエラーメッセージを全て表示させる
      • 今回の例では起きないが複数エラーがあったら改行して全て表示される

edit.html

  • new.htmlと同様の処理を追加
src/main/resources/templates/players/edit.html
      <form th:action="@{/players/{id}(id=*{id})}" th:method="put" th:object="${player}">
        <div class="form-group" th:classappend="${#fields.hasErrors('name')}? has-error">
          <label class="control-label">名前</label>
          <input class="form-control" type="text" th:field="*{name}" />
          <span class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('age')}? has-error">
          <label class="control-label">年齢</label>
          <input class="form-control" type="number" th:field="*{age}" />
          <span class="text-danger" th:if="${#fields.hasErrors('age')}" th:errors="*{age}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('team')}? has-error">
          <label class="control-label">チーム名</label>
          <input class="form-control" type="text" th:field="*{team}" />
          <span class="text-danger" th:if="${#fields.hasErrors('team')}" th:errors="*{team}"></span>
        </div>
        <div class="form-group" th:classappend="${#fields.hasErrors('position')}? has-error">
          <label class="control-label">守備位置</label>
          <input class="form-control" type="text" th:field="*{position}" />
          <span class="text-danger" th:if="${#fields.hasErrors('position')}" th:errors="*{position}"></span>
        </div>
        <button class="btn btn-default" type="submit">更新</button>
      </form>

動作確認

validation.gif

次回

40
27
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
40
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?