-
[Spring MVC] Form 검증Spring 2025. 11. 13. 22:10
Thymeleaf + Validation(jakarta) + BindingResult(spring) 조합으로 폼을 검증하고, 에러를 반환하여 사용자에게 메시지를 보여주는 간단한 작업을 정리해보겠습니다.

아무것도 입력하지 않고 제출 시, 아래와 같이 안내 메시지를 출력하는 작업입니다.

build.gradle
plugins { id 'java' id 'org.springframework.boot' version '3.5.7' id 'io.spring.dependency-management' version '1.1.7' } // ... dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' }
MemberForm.java
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; @Getter @Setter public class MemberForm { @NotEmpty(message = "이름을 입력해주세요.") private String name; @NotNull(message = "나이를 입력해주세요.") @Min(value = 18, message = "18세 이상") private Integer age; @Pattern(regexp = ".+@.+\\..+", message = "이메일 형식이 올바르지 않습니다.") private String email; }@NotEmpty, @NotNull 등 어노테이션으로 각 필드에 제약조건을 추가하고 메시지를 설정해줄 수 있습니다. 메시지는 검증 실패시 BindingResult 객체에 저장됩니다. 제약조건 종류는 아래와 같습니다.

에러 메시지는 messages.properties로 설정해줄 수도 있습니다.
# 기본 메시지 NotNull=값을 입력해주세요. NotEmpty=값을 입력해주세요. NotBlank=공백일 수 없습니다. Pattern=형식이 올바르지 않습니다. # MemberForm NotEmpty.memberForm.name=이름을 입력해주세요. NotNull.memberForm.age=나이를 입력해주세요.messages.properties 파일로 설정할 때, 한글이 깨진다면 인코딩 설정 문제입니다. 설정 > 에디터 > 파일 인코딩에서 전역 인코딩, 프로젝트 인코딩, 프로퍼티 파일 인코딩 값들을 UTF-8로 설정해주면 정상적으로 메시지가 표시됩니다.

MemberController.java
import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/members") @RequiredArgsConstructor public class MemberController { @GetMapping("/join") public String join(Model model) { model.addAttribute("memberForm", new MemberForm()); return "members/join"; } @PostMapping("/join") public String join(@Valid MemberForm memberForm, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "members/join"; // 회원가입 로직 return "redirect:/"; } }@Valid 명시 - 폼 객체에 대한 검증을 수행
BindingResult - 검증 오류 관련 데이터를 담고 있으며, 테스트하는 객체이다. 위 메서드에서는 오류가 있으면 MemberForm, BindingResult 객체와 함께 페이지를 반환하고, 아니라면 회원가입 로직을 수행하고 홈으로 리다이렉트한다.
join.html
<body> <form th:action="@{/members/join}" method="post" th:object="${memberForm}"> <label th:for="name"> 이름 <input type="text" th:field="*{name}" placeholder="이름을 입력하세요."/> </label> <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</p> <br> <label th:for="email"> 이메일 <input id="email" th:field="*{email}" type="email" placeholder="example@domain.com"/> </label> <p th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Email Error</p> <br> <label th:for="age"> 나이 <input type="text" th:field="*{age}" placeholder="나이를 입력하세요."/> </label> <p th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Age Error</p> <br> <button type="submit">Submit</button> </form> </body>클라이언트에서 수행하는 검증은 생략했습니다.
th:object - MemberForm 객체 바인딩
th:field - input 태그의 name, id값 설정 및 바인딩한 DTO 객체의 필드값 연결.
if (bindingResult.hasErrors()) return "members/join"; // 다시 반환하더라도, 입력했던 값을 그대로 유지할 수 있다.th:if - 에러 확인
th:errors - BindingResult에서 가져온 에러 메시지 출력
참고
Spring document
(https://spring.io/guides/gs/validating-form-input)
Github
(https://github.com/ehddnr3473/SpringMVC-Form-Validation)
'Spring' 카테고리의 다른 글
[Spring + Thymeleaf] messages 국제화 (0) 2025.11.14 [Spring] 전자정부프레임워크 crypto를 활용한 암호화 (0) 2024.06.17 [Spring] @RequestBody와 @ResponseBody를 사용해 JSON 형식의 데이터 주고받기 (0) 2023.08.31 스프링 IoC 컨테이너와 빈의 생성 (0) 2023.06.26