Hello World

객체 검증의 종결자 @Valid 본문

Spring/3.x

객체 검증의 종결자 @Valid

EnterKey 2017. 2. 10. 17:55
반응형

스프링 MVC에서 지원하는 @Valid를 통한 데이터 검증은 정말 놀랍다. 특히 브라우저에서 클라이언트가 입력자료를 넘겨줄 때 이 자료를 검증할 수 있는 모델을 매우 손쉽게 만들 수 있다는 점이다. @Valid는 스프링이 만든 기술은 아니며 최근 JSR-303이란 이름으로 채택된 서블릿 2.3 표준스펙 중 하나인데 매번 그렇듯 스프링은 이 새로운 표준을 확장하고 쉽게 사용할 수 있도록 스프링만의 방식으로 재편성해주었다. 


@Valid가 간소화 될 수 있었던 배경을 이해하고 응용할 수 있게끔 학습하는게 중요하겠지만 먼저 @Valid가 얼마나 대단한지 보여주기 위해 맛보기로 간단한 @Valid 예제를 살펴보고자 한다. 먼저 자바빈 객체를 하나 만들어보자.

public class User {

@Size(min=5, max=50) private String id;
@Size(min=5, max=50) private String password;
@Pattern(regexp="^[_0-9a-zA-Z-]+@[0-9a-zA-Z]+(.[_0-9a-zA-Z-]+)*$")
private String email;

… get/set 생략 …
}

그리고 이 JSP파일을 처리할 수 있는 컨트롤러를 하나 만들어 보자. 최초에 문서를 불러들이는 Get과 송신을 위해 필요한 Post, 2가지가 필요하다. 그리고 세션으로 상태유지를 할 수 있게끔 해당 요소를 @SessionAttributes로 공유해주는 것까지 해주도록 하자.

이 몇줄의 코드를 설명시키기 위해 토비의 스프링에서 무려 200쪽이 넘는 공간을 할애하여 설명하고 있으므로 여기서는 가급적 자세한 설명을 생략하도록 하겠다. (생략의 가장 중대한 이유는 필자도 잘 모른다는 사실이지만 그것은 중요치 않다.... :D) 먼저 @ModelAttribute User user와 같은 형태로 클라이언트의 요청을 커맨트 패턴으로 받는다. 그리고 이 모델에 검증을 하기 위해 위의 예제와 같이 @valid라는 검증 어노테이션을 붙인다. 그리고.... 더 해야 할 일은...... 없다.

짜잔! 이것은 기본적인 검증 모델 설계가 끝난 셈이다. 믿지 않겠지만 진짜다. 스프링 MVC는 이와같은 간단한 어노테이션만으로도 검증모델을 유지하며 검증 결과를 BindingResult 객체로 전달해주는 역할을 담당한다. 먼저 자바빈 객체를 살펴보며 @Valid가 무엇인지 부터 알아보자.

@Valid는 그동안 논란이 되왔던, 검증모델이 프리젠테이션 계층에 위치해야 되는지, 서비스 계층에 위치해야 하는지에 대한 논란을 어느 정도 통일시켜주는 표준기술이다. 그러나 역설적으로 @Valid는 그동안의 논란을 뒤집고 검증모델을 프리젠테이션 계층도, 서비스 계층도 아닌 도메인 계층에 삽입할 수 있게 하였다. 즉 @Valid는 아예 원천적으로 등록 오류를 피하기 위해 객체 자체에 검증모델 주입하는 방식을 채택하고 있다.

@Valid에는 기본적으로 14개의 검증 어노테이션을 제공한다.

@AssertFalse : false 값만 통과 가능
@AssertTrue : true 값만 통과 가능
@DecimalMax(value=) : 지정된 값 이하의 실수만 통과 가능
@DecimalMin(value=) : 지정된 값 이상의 실수만 통과 가능
@Digits(integer=,fraction=) : 대상 수가 지정된 정수와 소수 자리수보다 적을 경우 통과 가능
@Future : 대상 날짜가 현재보다 미래일 경우만 통과 가능
@Past : 대상 날짜가 현재보다 과거일 경우만 통과 가능
@Max(value) : 지정된 값보다 아래일 경우만 통과 가능
@Min(value) : 지정된 값보다 이상일 경우만 통과 가능
@NotNull : null 값이 아닐 경우만 통과 가능
@Null : null일 겨우만 통과 가능
@Pattern(regex=, flag=) : 해당 정규식을 만족할 경우만 통과 가능
@Size(min=, max=) : 문자열 또는 배열이 지정된 값 사이일 경우 통과 가능
@Valid : 대상 객체의 확인 조건을 만족할 경우 통과 가능

기본 객체는 대부분의 경우 위의 14가지 어노테이션으로도 통과가 가능하겠지만 생성객체나 좀 더 엄격한 규칙을 위해서는 직접 검증 어노테이션을 구현할 수도 있다. 직접 어노테이션을 구현하는 부분은 다음에 다뤄보기로 하고 지금은 위의 예제가 어떤 방식으로 동작하는 지에 좀 더 집중하도록 하겠다.

이제 위와 같은 어노테이션을 도메인 모델에 적용시켰다면 마지막으로 스프링은 @Valid를 컨트롤러에 적용시킴으로써 깜찍한 마법을 부려준다. 위의 예제에서 @ModelAttributes @Valid User user는 위의 어노테이션 설명에서도 보았듯이 대상 객체에 정의 되있는 확인 조건을 만족시키는 역할을 담당한다. 스프링 MVC는 이런 조건을 만족시키지 못할 경우 내부 컨트롤러에 의해 자동적으로 bindingResult 객체에 담겨저 컨트롤러로 돌아오게 된다.

즉 위의 예제는 /join URL을 Post방식으로 호출할 경우 자연스럽게 @ModelAttribute가 해당 파라미터들을 User객체로 캡슐화 시킴과 동시에 내부에 규약되있는 객체 검을을 @Valid가 발동되면서 오류가 있을 경우 오류 정보를 함께 전송한다. 그리고 마지막으로 스프링 컨테이너에 의해 오류정보는 bindingResult 객체로 분류되면서 끝이 난다.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form modelAttribute="user" autocomplete="off">
<h4><strong>회원가입</strong></h4>
<div class="clearfix">
<div class="left">
<form:label path="id">아이디</form:label>
</div>
<div class="left">
<form:input path="id"/>
<form:errors path="id" />
</div>
</div>
<div class="clearfix">
<div class="left">
<form:label path="password">비밀번호</form:label>
</div>
<div class="left">
<form:input path="password"/>
<form:errors path="password" />
</div>
</div> 
<div class="clearfix">
<div class="left">
<form:label path="email">이메일</form:label>
</div>
<div class="left">
<form:input path="email"/>
<form:errors path="email" />
</div>
</div>
<div class="clearfix">
<div class="left"></div>
<div class="left"></div>
</div>
<input type="submit" value="업로드" />
</form:form>


아래는 위의 JSP코드와 컨트롤러를 이용하여 만든 예제 회원가입 폼이다.

위의 코드를 적용시키기 위해서는 Spring에서 제공하는 form 태그를 이해해야 하는데 스프링 폼은 나중에 깊게 다루기로 하고 일단 기본적으로 이 스프링 폼을 통해 에러객체와 폼객체를 완벽하게 분리시켰다는 사실만 기억하자.

<form:errors>는 컨트롤러에서 전달받은 에러 객체를 컨트롤하는 역할을 담당하는데 현재 별도의 에러 메시지 설정이 없으므로 기본 에러가 표시된다. 만약 에러메시지를 바꾸고 싶다면 도메인 객체에 삽입한 검증 모델에 message라는 값을 더해주면 된다.

@Size(min=5, max=50, message="5자에서 50자 사이의 값만 가능합니다") private String id;

또 하나의 방법은 messages.properties를 이용하여 이런 에러메시지를 관리하는 방법인데 이 방법은 좀 더 스프링 검증 모델을 완벽히 습득한 뒤에 작성하도록 하겠다. 생각같아선 가급적 @Valid에 대해 완벽하게 다루고 싶었지만 생각보다 복잡한 방식으로 이루어지고 있는데다 확장포인트를 잡기가 어려워 여기서 대략적인 설명만 달아놓을 수 밖에 없었다.

이 문서는 기본적인 설명만을 다루고 있으므로 예제나 방식을 실제 서비스에 적용할 때는 좀 더 많은 관련 문서를 참고해 보고 자신만의 설계 모델을 구축해야 할 것이다.


출처: http://springmvc.egloos.com/509029

반응형
Comments