2010년 4월 4일 일요일

Spring 3.0 Validation Part3

Part1,Part2는 기본적인 스프링에서 JSR-303
Validation 사용 방법에 대해서 설명 드렸습니다.
이번 Part는 Custom Validation에 대해서
말씀 드리겠습니다.
먼저 User 도메인 클래스 보면 아래와
같습니다.
public class User {

@NotEmail
private String email;

.....
}


"@NotEmail"은 제가 직접 만든 검증
annotation 입니다.
이제 부터 작성 방법에 대해서 말씀 드리겠습니다.

  • NotEmail Annotation 작성 방법
custom validation을 만들려면 2개의 클래스가 필요 합니다.
첫번째는 검증 annotation 클래스 이며 나머지 하나는
annotation을 검증할 validator 클래스 입니다.
이 두클래스의 참조 관계는 서로 의존 하는 관계
입니다.
package org.springshowcase.mvc;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintPayload;

@Documented
//@Constraint(validatedBy = EmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmail {
public abstract String message() default "Not Email Format!";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends ConstraintPayload>[] payload() default {};
}


"@Contraint" 부분을 주석 처리 하고 compile을 합니다.
이유는 아직 "EmailValidator" 클래스가 존재 하지 않기
때문입니다.

  • EmailValidator 클래스 작성 방법

package org.springshowcase.mvc;

import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class EmailValidator implements ConstraintValidator<NotEmail, String> {

@Autowired
@Qualifier("emailPattern")
String pattern;

public void initialize(NotEmail constraintAnnotation) {
// nothing to initialize
}

public boolean isValid(String value, ConstraintValidatorContext context) {
Pattern EMAIL_PATTERN = Pattern.compile(this.pattern);
return EMAIL_PATTERN.matcher(value).matches();
}
}
반드시 "ContraintValidator" 인터페이스를 구현 해야 합니다
"@Autowired" 어노테이션을 보면 스프링 annotation 입니다.
이 얘기는 아래와 같이 스프링 빈을 선언 하면
<mvc:annotation-driven />

"ContraintValidator" 인터페이스를 구현한 모든 클래스는
스프링 ApplicationContext에서 이러한 클래스들을
스프링 빈으로 생성합니다.
이말은 Validator에 다른 스프링 빈을 injection을 할 수있다는
뜻 입니다.
예제를 통해서 email 정규식을 일부러 스프링 빈으로 설정하고
injection을 시켰습니다.
아래는 injection 당한 빈 입니다.
<bean id="emailPattern" class="java.lang.String">
<constructor-arg index="0" type="java.lang.String"
value=".+@.+\\.[a-z]+" />
</bean>

  • NotEmail Annotation 재컴파일
이제 "EmailValidator"가 생성이 되었기 때문에
"NotEmail" 어노테이션 클래스의 주석을 해제하고
재컴파일 합니다.

package org.springshowcase.mvc;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintPayload;

@Documented
@Constraint(validatedBy = EmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmail {
public abstract String message() default "Not Email Format!";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends ConstraintPayload>[] payload() default {};
}



  • Message Bundle 작성 방법
이제 새로운 custom validator를 작성이 끝났습니다.
새로운 annotation을 적용할 도메인 클래스에
선언 하면 됩니다.
메세지 번들 작성 방법은 아래와 같이 하면 됩니다.
NotEmail.user.email=이메일 형식이 틀립니다.

  • Spring Validation VS JSR-303
JSR-303 스펙에 대해서 확정을 하기 위한 투표를
하려고 했을때 스프링 진영에서는 참석을 하지
않았다고 합니다. 그래서 jboss 진영에서 심기가
좋지 않았다는 얘기가 있습니다.
역시 둘은 앙숙인듯....
아무래도 스프링 입장에서 자기들 validation이
있는데 굳이 JSR-303 스펙을 넣는게 그다지
좋지는 않았을 것 같습니다.
anyway!
JSR-303은 제가 도메인 클래스를 얘를 들었지만
사실 도메인 클래스만 해당 되는 것은 아닙니다.
모든 클래스(Service,DAO,..)에서 적용이 가능
합니다.
직접 써보니 JSR-303은 장점이 상당히 많았습니다.
첫째 검증 로직의 중복이 없습니다.
대부분 스프링 validation은 매요청시 작성 한거에
반해서 JSR-303은 도메인에 설정 하기때문에
검증 로직이 좀더 명확하고 코딩수도 적다는 얘기
입니다. 그리고 메세지 작성 방법도 직관적이기
때문에 관리도 수월 합니다.
반면 단점이 한나 있습니다. 좀 유연하지 않는다는
문제 입니다.
무슨 얘기냐 예를 들어서 id,name,email 이런 3개의
속성이 있다고 하고 모두 NotNull 조건이라고
설정을 합니다.
insert일 경우야 당연히 NotNull이지만
name만 update를 할경우 id,name 두
속성만 있으면 되는데 validation 조건이
모두 NotNull 조건이기 때문에 굳이
필요 없는 email에 기존 값을 채워서
보내야 한다는 것입니다.
즉 케이스별 검증 체크를 선택적으로 할 수
없다는 것입니다.
이런 이유는 예측컨데 jboss 진영에 힘이
있었지 않나 생각 합니다.
hibernate인 경우는 전체 업데이트를
체크 하기 때문이죠..
그래서 제가 개인적으로 시간이 되면 선택적으로
validation을 수행하는 util 클래스를 만드려고 합니다.
(언제가 될지 모르지만..)
그리고 한가지 더 현재 JSR-303 라이브러리와 구현체
라이브러리가 release가 아닌 running 중이기 때문에
라이브러리의 버전 진행도 유심히 모니터링
할 필요가 있습니다.
개인적으로 JSR-303은 실무에서 사용해도
훌륭한 개발 도구가 될 것 같습니다.

  • 소스 다운 로드
본 예제는 제가 진행하는 오픈 소스 "ssc-mvc"를 체크아웃
받으시면 됩니다.
자세한 내용은 오픈 소스 사이트를 참고 하시기 바랍니다.

댓글 없음:

댓글 쓰기