implementation 'org.springframework.boot:spring-boot-starter-validation'
Ex) @NotBlank, @Size, @Email, @Min, @Max 등 다양한 에노테이션을 사용하여 필드에 대한 유효성 검사 규칙을 정의할 수 있음.Ex
@Getter
@Setter
public class ArticleDto {
@NotBlank(message = "제목은 필수 입력 항목입니다.")
@Size(max = 100)
private String title;
@NotBlank(message = "내용은 필수 입력 항목입니다.")
private String content;
}
@PostMapping("/create")
public String createArticle(@Valid ArticleDto articleDto, BindingResult bindingResult) {
// BindingResult : @Valid 에노테이션의 검증 결과를 담고 있는 객체.
if (bindingResult.hasErrors()) {
return "/article_form";
}
articleService.createArticle(articleDto.getTitle(), articleDto.getContent());
return "redirect:/article/list";
}
@Valid와 BindingResult를 추가했음.BindingResult는 항상 @Valid 매개변수 바로 뒤에 위치해야됨.검증할 객체 바로 뒤에 위치해야됨.bindingResult.hasErrors(), 즉 BindingResult에 오류가 담겨있을 경우에는article_form 뷰 템플릿을 return해서 글쓰기 화면으로 돌아감.<!-- layout.html을 상속 받도록 설정. -->
<html layout:decorate="~{layout}">
<!-- 부모 템플릿(layout.html)의 layout:fragment="content" 부분에 삽입되도록 설정. -->
<div layout:fragment="content" class="container my-3">
<h5 class="my-3 border-bottom pb-2">게시판 글쓰기</h5>
<form th:action="@{/article/create}" method="post" th:object="${articleDto}">
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="error : ${#fields.allErrors()}" th:text="${error}"></div>
</div>
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" placeholder="제목을 입력해 주세요." name="title" id="title" class="form-control">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea name="content" placeholder="내용을 입력해 주세요." id="content" class="form-control" rows="10" style="resize: none"></textarea>
</div>
<button type="submit" class="btn btn-primary my-2">등록하기</button>
</form>
</div>
</html>
- 아무것도 입력하지 않고 하단에 등록하기 버튼을 누르면 우측처럼 출력됨. | - 검증 메시지가 출력된 모습. |


<!-- layout.html을 상속 받도록 설정. -->
<html layout:decorate="~{layout}">
<!-- 부모 템플릿(layout.html)의 layout:fragment="content" 부분에 삽입되도록 설정. -->
<div layout:fragment="content" class="container my-3">
<h5 class="my-3 border-bottom pb-2">게시판 글쓰기</h5>
<form th:action="@{/article/create}" method="post" th:object="${articleDto}">
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="error : ${#fields.allErrors()}" th:text="${error}"></div>
</div>
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" placeholder="제목을 입력해 주세요." name="title" id="title" class="form-control">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea name="content" placeholder="내용을 입력해 주세요." id="content" class="form-control" rows="10" style="resize: none"></textarea>
</div>
<button type="submit" class="btn btn-primary my-2">등록하기</button>
</form>
</div>
</html>
<!-- layout.html을 상속 받도록 설정. -->
<html layout:decorate="~{layout}">
<!-- 부모 템플릿(layout.html)의 layout:fragment="content" 부분에 삽입되도록 설정. -->
<div layout:fragment="content" class="container my-3">
<h5 class="my-3 border-bottom pb-2">게시판 글쓰기</h5>
<form th:action="@{/article/create}" method="post" th:object="${articleDto}">
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="error : ${#fields.allErrors()}" th:text="${error}"></div>
</div>
<div class="mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" placeholder="제목을 입력해 주세요." th:field="*{title}" class="form-control">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea placeholder="내용을 입력해 주세요." th:field="*{content}" class="form-control" rows="10" style="resize: none"></textarea>
</div>
<button type="submit" class="btn btn-primary my-2">등록하기</button>
</form>
</div>
</html>
