SpringBoot + JPA + Thymeleaf로 간단한 CRUD를 만드는 ③~Validation 추가~

내용



  • 지난번 계속
  • SpringBoot로 간단한 CRUD 앱 만들기
  • 이번은 입력 영역에 밸리데이션을 걸다
  • 이름과 연령을 필수 항목으로 설정
  • 연령은 0~150의 범위내로 한다
  • 팀 이름은 20자까지




  • 절차


  • entity에 유효성 검사 설정 추가
  • controller에 오류 제어 추가
  • 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. 컨트롤러에 오류 제어 추가


  • 오류가 발생하면 원래 화면으로 돌아가는 프로세스를 추가합니다.
  • 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()

    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로부터 플레이어를 받게 되었으므로, 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>
    

    동작 확인


  • 여기까지 수정한 상태에서 http://localhost:8080/players 에 액세스하면 다음과 같은 동작이 된다



  • 다음 번


  • 다음은 여기
  • 좋은 웹페이지 즐겨찾기