스프링 MVC

유기훈·2025년 2월 18일

Validation

에러 메시지

플레이스홀더

아래와 같이 Bean Validation 사용 시에 message에 {변수명}을 입력할 수 있음. 아래와 같이 작성하면, "값은 1에서 10사이여야 합니다."라는 에러 메시지가 출력됨

@Data
public class MyRequestDTO {

    @NotNull
    @Range(min = 1, max = 100, message = "값은 {min}에서 {max} 사이여야 합니다.")
    private Integer age;
}

BindingResult

BindingResult란

BindingResult는 Spring MVC에서 폼 검증 시 오류 정보를 담는 객체이다. Thymeleaf를 사용할 때 이 BindingResult를 활용하여 입력값 유지와 에러 메시지 표시를 쉽게 구현할 수 있다.

BindingResult 사용 예시

1. DTO 정의

@Data
public class UserForm {
    
    @NotBlank(message = "이름은 필수 입력 항목입니다.")
    private String name;

    @Email(message = "올바른 이메일 형식을 입력하세요.")
    @NotBlank(message = "이메일은 필수 입력 항목입니다.")
    private String email;

    @Size(min = 6, max = 12, message = "비밀번호는 6~12자 사이여야 합니다.")
    private String password;
}

2. 컨트롤러 정의

@Controller
public class UserController {

    @GetMapping("/register")
    public String showForm(Model model) {
        model.addAttribute("userForm", new UserForm());
        return "register";
    }

    @PostMapping("/register")
    public String register(@Validated @ModelAttribute("userForm") UserForm userForm, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return "register"; // 검증 실패 시 다시 폼 페이지로 이동
        }
        return "success"; // 성공 시 성공 페이지로 이동
    }
}

3. Thymeleaf 폼

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>회원 가입</title>
</head>
<body>
    <h2>회원 가입</h2>
    <form th:action="@{/register}" th:object="${userForm}" method="post">

        <!-- 이름 입력 -->
        <label for="name">이름:</label>
        <input type="text" id="name" th:field="*{name}" />
        <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" style="color:red"></span>
        <br>

        <!-- 이메일 입력 -->
        <label for="email">이메일:</label>
        <input type="text" id="email" th:field="*{email}" />
        <span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" style="color:red"></span>
        <br>

        <!-- 비밀번호 입력 -->
        <label for="password">비밀번호:</label>
        <input type="password" id="password" th:field="*{password}" />
        <span th:if="${#fields.hasErrors('password')}" th:errors="*{password}" style="color:red"></span>
        <br>

        <button type="submit">가입하기</button>
    </form>
</body>
</html>

BindingResult 사용 시 주의사항

1. BindingResult는 검증 대상 바로 뒤에 위치해야 함

public String register(@Validated @ModelAttribute("userForm") UserForm userForm, BindingResult bindingResult)

2. th:field와 th:errors는 th:object와 함께 사용해야 함
Thymeleaf에서 th:field는 th:object와 연동되므로 폼의 th:object를 선언해야 한다.
- th:field="{name}" → userForm.name 필드와 자동 매핑됨
- th:errors="
{name}" → 해당 필드의 오류 메시지를 자동 출력

<form th:action="@{/register}" th:object="${userForm}" method="post">

3. 검증 실패 시 입력값이 유지되어야 함.
th:field를 사용하면 검증 실패 후에도 사용자가 입력한 값이 유지된다.
Spring이 userForm의 값을 다시 모델에 담아 자동으로 기존 입력값을 채운다.

<input type="text" id="name" th:field="*{name}" />

4. @ModelAttribute와 BindingResult 활용

  • @ModelAttribute를 사용하면 폼 데이터를 자동으로 DTO로 변환한다.
  • BindingResult를 사용하면 폼에서 발생한 모든 오류를 가져와서 Thymeleaf에서 활용 가능하다.
profile
개발 블로그

0개의 댓글