java-school logo

빈 검증(Bean Validation)

Spring MVC 프로젝트에서 폼 입력에 바인딩되는 빈을 검증하는 예제를 실습한다. 실습 과정은 다음과 같다.

  1. Hibernate Validator 의존 라이브러리를 pom.xml에 추가
  2. 폼 입력에 바인딩 되는 자바 빈에 유효성 검사 규칙 선언
  3. 컨트롤러의 요청 핸들러 메서드에 빈 검증 로직 추가
  4. JSP에 스프링 태그 라이브러리를 적용하여 검사 에러가 출력되도록 수정

회원 가입에서의 빈 검증

Hibernate Validator 의존 라이브러리를 pom.xml에 추가한다.

pom.xml
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>5.4.0.Final</version>
</dependency>

pom.xml의 내용이 변경되었으니 이클립스와 동기화한다. 컨텍스트 메뉴의 Maven - Update Project Cofiguraion을 실행한다. 스프링 설정 파일에 <mvc:annotation-driven /> 설정이 있는지 확인한다. web.xml에 요청 파라미터의 캐릭터 셋을 "UTF-8"로 바꾸는 필터가 설정되어 있는지 확인한다.

회원 가입 폼 입력에 바인딩되는 빈에, JSR-303의 빈 검증 어노테이션 또는 hibernate-validator 구현체에서 제공하는 빈 검증 어노테이션을 사용하여, 검사 규칙을 선언한다. 아래 어노테이션에서 @NotNull과 @Size(min=,max=)는 JSR-303 스펙에서, @Email은 hibernate-validator 구현체에서 제공한다.

User.java
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;

@NotBlank(message="이메일 형식이 아닙니다.")
@Email(message="이메일 형식이 아닙니다.")
private String email;

@Size(min=4, message="패스워드는 4자 이상이어야 합니다.")
private String passwd;

@Size(min=2, message="이름은 2자 이상이어야 합니다.")
private String name;

@Size(min=6, max=20, message="모바일폰 번호형식이 아닙니다.")
private String mobile;

회원 가입 폼 페이지로 포워딩하는 요청 핸들러 메서드(아래 첫 번째 signUp() 메서드)에 내용이 없는 빈 객체(User 객체)를 생성해 뷰에 전달해야 한다. 이건 스펙이니 따라야 한다. 회원 가입을 처리하는 요청 핸들러 메서드(아래 두 번재 signUp() 메서드)에 빈 검증 로직을 추가한다. 두 번재 signUp() 메서드의 매개 변수 리스트에서 @Valid 어노테이션이 적용된 매개 변수 다음에는 반드시 BindingResult 타입의 매개 변수를 선언해야 한다. 그렇지 않으면 HTTP 400 에러가 발생한다.

UsersController.java
import javax.validation.Valid;
import org.springframework.validation.BindingResult;

@RequestMapping(value="/signUp", method=RequestMethod.GET)
public String signUp(Model model) {
    model.addAttribute(WebContants.USER_KEY, new User());
    
    return "users/signUp";
}

@RequestMapping(value="/signUp", method=RequestMethod.POST)
public String signUp(@Valid User user, BindingResult bindingResult) {
    //유효성 검사
    if (bindingResult.hasErrors()) { //검증에 실패한 빈은 BindingResult에 담겨 뷰에 전달된다.
        return "users/signUp";
    }
	
    //...중간 생략...
}

JSP를 아래를 참고하여 수정한다. <sf:errors> 태그는 사용자에게 검증 에러를 표시하는 스프링 폼 태그이다.

signUp.jsp
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>

<sf:form id="signUpForm" action="signUp" method="post" commandName="user" 
        onsubmit="return check();">
<sf:errors path="*" cssClass="error" />
<table>
<tr>
    <td style="width: 200px;">이름(Full Name)</td>
    <td style="width: 390px">
        <sf:input path="name" /><br />
        <sf:errors path="name" cssClass="error" />
    </td>
</tr>
<tr>
    <td>비밀번호(Password)</td>
    <td>
        <sf:password path="passwd" /><br />
        <sf:errors path="passwd" cssClass="error" />
    </td>
</tr>
<tr>
    <td colspan="2" style="text-align: center;font-weight: bold;">
        Email이 아이디로 쓰이므로 비밀번호는 Email계정 비밀번호와 같게 하지 마세요.
    </td>
</tr>
<tr>
    <td>비밀번호 확인(Confirm)</td>
    <td><input type="password" name="confirm" /></td>
</tr>
<tr>
    <td>Email</td>
    <td>
        <sf:input path="email" /><br />
        <sf:errors path="email" cssClass="error" />
    </td>
</tr>
<tr>
    <td>손전화(Mobile)</td>
    <td>
        <sf:input path="mobile" /><br />
        <sf:errors path="mobile" cssClass="error" />
    </td>
</tr>
</table>
<div style="text-align: center;padding-bottom: 15px;">
    <input type="submit" value="확인" />
</div>
</sf:form>

에러 메시지를 위한 스타일을 CSS 파일에 추가한다.

screen.css
.error {
	color: red;
}

테스트 화면

가입 페이지 방문
빈 검증 실패

참고