Spring Boot/STUDY

[Spring Boot] @Valid을 통한 게시글 등록 유효성 검사

코맹 2024. 6. 19. 20:15

 

💥 <textarea>를 사용해서 게시글을 등록할 때 입력 값을 적지 않아도 빈 값이 들어가는 문제가 발생

이를 해결하기 위해 Validation을 사용해보겠다.

 

build.gradle에 입력값 검증 Spring Boot Validation 디펜던시 추가
implementation 'org.springframework.boot:spring-boot-starter-validation'

  • bulid 된 것 확인

 

/validation/BoardForm.java 생성

package com.eunji.backboard.validation;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardForm {
  @Size(max=250)
  // @NotEmpty(message = "제목은 필수입니다.")
  @NotBlank(message = "제목은 필수입니다.")
  private String title;

  @NotBlank(message = "제목은 필수입니다.")
  private String content;
  
}
  • Entity에 추가하게 되면 복잡해질 수 있음
  • 따라서, 유효성 검사할 필드만 따로 class 만들어서 빼주는 것이 편리함
@NotEmpty -> @NotBlank로 변경
- NotEmpty는 스페이스를 허용해서 스페이스를 입력하면 게시글 등록되는 문제 발생
- NotBlank는 스페이스 허용하지 않음

 

 

/controller/BoardController.java에 BoardForm을 전달(GetMapping, PostMapping 모두)
@GetMapping("/create")
  public String create(BoardForm boardForm){
    return "board/create";
  }

  @PostMapping("/create")
  public String create(@Valid BoardForm boardForm,
                       BindingResult bindingResult) {
    if(bindingResult.hasErrors()) {
      return "board/create";    // 현재 html에 그대로 머무르기
    }

    // this.boardService.setBoard(title, content);
    this.boardService.setBoard(boardForm.getTitle(), boardForm.getContent());
    return "redirect:/board/list";
  }
  • @GetMapping시 create() 메서드에서 파라미터로 boardForm을 보냄
  • 이후 create.html에서 th:object="${boardForm}"으로 사용할 수 있음

BindingResult가 궁금하다면 아래 링크에서 더 알아볼 수 있다😎

https://iieunji023.tistory.com/21

 

[Spring Boot] BuildResult란?

Spring Boot JPA 프로젝트를 진행하면서 게시판 등록 시 유효성 검사를 하기 위해 @Valid를 사용했다.이 과정에서 BindingResult를 매개변수로 받아서 에러가 있는지 없는지 확인했는데 무엇인지 정리해

iieunji023.tistory.com

 

 

 

create.html

<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" layout:decorate="~{layout}">
  <div layout:fragment="main-content" class="container my-3">
    <h5 class="border-bottom my-3 pb-2">게시글 등록/수정</h5>

    <form th:action="@{/board/create}" th:object="${boardForm}" method="post">
      <div th:replace="~{errors :: formErrorFragment}"></div>
      <div class="mb-3">
        <label for="title" class="form-lable">글제목</label>
        <input type="text" th:field="*{title}" class="form-control">
      </div>
      <div class="mb-3">
        <label for="content" class="form-lable">글내용</label>
        <textarea th:field="*{content}" class="form-control" rows="10"></textarea>
      </div>
      <div class="d-flex justify-content-end">
        <input type="submit" value="저장"  class="btn btn-sm btn-primary">
        <a href="/board/list" class="btn btn-sm btn-secondary mx-1">목록</a>
      </div>
    </form>
  </div>
</html>
  • th:object = ${boardForm}
    • GetMapping에서 전달 받는 값
  • th:field="*{title}"을 통해 name, id, value를 지정
    • 이때 *{} 안의 변수는 boardForm 클래스 내에 있는 변수를 사용해야 함!

댓글 기능도 동일하게 진행하면 된다.

 

detail.html
 <!-- 답변기능 영역 -->
<form th:action="@{|/reply/create/${board.bno}|}" th:object="${replyForm}" method="post" class="my-3">
   <div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
       <div th:each="err : ${#fields.allErrors()}" th:text="${err}"></div>
   </div>
   <textarea name="content" th:field="*{content}" rows="10" class="form-control"></textarea>
   <div class="d-flex justify-content-end mt-2">
      <input type="submit" value="댓글등록" class="btn btn-sm btn-primary mx-1">
      <a href="/board/list" class="btn btn-sm btn-secondary">목록</a>
   </div>
</form>

 

여기서 th:object="${replyForm}"는 @GetMapping에서 전달받는 값으로 BoardController의 detail() 메서드 파라미터로 보내줘야함


 

중복되는 error 코드 빼기

errors.html

<div th:fragment="formErrorFragment" class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
  <div th:each="err : ${#fields.allErrors()}" th:text="${err}"></div>
</div>

 

create.html과 detail.html에서 반복되던 error코드 대신 아래 코드로 변경

<div th:replace="~{errors :: formErrorFragment}"></div>

 

 


 

유효성 검사에 사용할 수 있는 어노테이션
@Null  // null만 혀용합니다.
@NotNull  // null을 허용하지 않습니다. "", " "는 허용합니다.
@NotEmpty  // null, ""을 또는 리스트 [] 빈값 허용하지 않습니다. " "는 허용합니다.
@NotBlank  // null, "", " " 모두 허용하지 않습니다.

@Email  // 이메일 형식을 검사합니다. 다만 ""의 경우를 통과 시킵니다. @Email 보다 아래 나올 @Patten을 통한 정규식 검사를 더 많이 사용합니다.
@Pattern(regexp = )  // 정규식을 검사할 때 사용됩니다.
@Size(min=, max=)  // 문자길이를 제한할 때 사용, int는 불가!

@Max(value = )  // 숫자 value 이하의 값을 받을 때 사용됩니다.
@Min(value = )  // 숫자 value 이상의 값을 받을 때 사용됩니다.

@Pattern(regexp = )		// 정규표현식으로 검증식 세울 수 있다.

@Positive  // 값을 양수로 제한합니다.
@PositiveOrZero  // 값을 양수와 0만 가능하도록 제한합니다.

@Negative  // 값을 음수로 제한합니다.
@NegativeOrZero  // 값을 음수와 0만 가능하도록 제한합니다.

@Future  // 현재보다 미래
@Past  // 현재보다 과거

@AssertFalse  // false 여부, null은 체크하지 않습니다.
@AssertTrue  // true 여부, null은 체크하지 않습니다.

@Valid	// 해당 object validation 실행