13.Validation
Spring에서는 사용자가 입력한 값에 대한 유효성을 체크하기 위해 Spring Validator 또는 JSR-303 Validator를 사용할 수 있도록 지원하고 있다.
Spring MVC에서는 Spring Validator를 이용하여 입력 필드의 값에 대해 Validation Check를 수행하고 Errors 객체를 통해 에러 메시지를 출력해 줄 수 있도록 지원한다. 또한 Errors 객체에 담겨진 에러 메시지는 jsp 페이지에서 form:errors 태그를 통해 출력될 수 있다.
ValidatorUtils 사용
필수 입력 필드에 대해 Validation Check를 수행하고 에러 메시지를 출력할 수 있도록 지원한다. 이것은 ValidatorUtils를 사용하여 간단히 구현할 수 있다. 다음은 Validator 인터페이스를 구현한 UserValidator.java 클래스의 일부이다.
public class UserValidator implements Validator { public boolean supports(Class clazz) { return UserVO.class.isAssignableFrom(clazz); } public void validate(Object object, Errors errors) { // validationUtils를 이용하여 입력값이 비었는지 체크 ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "required", new Object[] { "userName" }, "Enter your name"); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "required", new Object[] { "password" }, "Enter your password");
Errors 사용
Validation Check 결과 발생된 Error를 Errors 객체를 사용하여 저장함으로써 해당 필드에 대해 정의된 에러 메시지를 출력할 수 있도록 지원하며 그 예는 다음과 같다.
public class UserValidator implements Validator { public boolean supports(Class clazz) { return HelloVO.class.isAssignableFrom(clazz); } public void validate(Object object, Errors errors) { HelloVO helloVO = (HelloVO) object; if (helloVO.getPassword().length() < 6) errors.rejectValue("password", "error.password.tooshort"); if (!helloVO.getPassword().equals(helloVO.getConfirmPassword())) errors.rejectValue("confirmPassword", "error.confirm"); } }
Validation Error가 있는 경우 메시지 리소스 파일에 미리 정의된 error.password.tooshort, error.confirm 등의 메시지가 출력될 것이다.
생성한 Validator를 활용하기 위해서는 해당 Validator를 Inject하여 사용하거나 Controller 클래스 내에 @InitBinder 메소드를 정의하고 해당 메소드의 입력 인자로 전달된 Binder에 해당 Validator를 셋팅하여 활용할 수 있다.
Validation Error를 JSP 페이지에서 쉽게 출력하기 위해 Spring MVC에서 제공하는 form 태그 중 <form:errors> 태그를 사용할 수 있다. 이 태그를 사용하기 위해서는 다음과 같은 절차를 따르도록 한다.
태그 라이브러리 등록
Spring form 태그 라이브러리를 사용하기 위해서는 spring-form.tld 파일이 필요하며 이는 spring-webmvc-x.x.x.jar 파일에 포함되어 있다. 이 form 태그를 사용하기 위해서는 JSP 페이지에 다음과 같이 taglib 정의가 추가되어야 한다.
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form> 태그 사용
form 태그를 사용하려면 commandName 속성을 지정해야 하는데 이 이름은 JSP 페이지에서 사용되는 commandName과 일치해야 하며 commandClass와 같은 타입의 객체이어야 한다. commandName에 특정 이름을 부여하지 않으면 기본 값은 command로 셋팅된다. form 태그는 여러가지 폼 입력 태그들을 갖는다. 그 중, Validation Error 표현을 위한 태그는 <form:errors>이며 이 태그는 속성으로 path를 가진다. path 값으로 "*" 값을 주게 되면 commandClass가 가지는 모든 속성에 대한 Error 메시지를 출력하게 된다. 다음은 <form:errors> 태그가 정의되어 있는 getUser.jsp 파일의 일부이다.
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <tr> <td> Name :</td> <td><form:input path="userName" />(required)</td> <td><form:errors path="userName" /></td> </tr> <tr> <td>password :</td> <td><form:password path="password" />(required, 6자이상입력)</td> <td><form:errors path="password" /></td> </tr>
Spring 3 이후부터는 Bean Validation에 대한 표준을 정의한 JSR-303 Spec.을 지원하고 있다. Validation은 선언적인 형태와 프로그램적인 형태로 구분할 수 있으며 Hibernate Validator와 같은 JSR-303 Spec.을 구현한 구현체를 연계하여 처리된다.
JSR-303은 Bean Validation을 위한 표준을 정의하고 있으며 특정 어플리케이션을 구성하는 도메인 클래스에 대해 JSR-303 Annotation을 활용하여 Validation Constraints를 부여하게 되면 런타임시에 이를 기준으로 Validation Check가 이루어지게 된다. 다음은 JSR-303 Spec.에서 제시한 Annotation 목록이다.
Annotation | Supported Type | Description |
---|---|---|
@AssertFalse | boolean, Boolean | 해당 속성의 값이 false인지 체크한다. |
@AssertTrue | boolean, Boolean | 해당 속성의 값이 true인지 체크한다. |
@DecimalMax | BigDecimal, BigInteger, String, byte, short, int, long and primitive type에 대한 wrappers | 해당 속성이 가질 수 있는 최대값을 체크한다. |
@DecimalMin | BigDecimal, BigInteger, String, byte, short, int, long and primitive type에 대한 wrappers | 해당 속성이 가질 수 있는 최소값을 체크한다. |
@Digits | BigDecimal, BigInteger, String, byte, short, int, long and primitive type에 대한 wrappers | 해당 속성이 가질 수 있는 정수부의 자리수와 소수부의 자리수를 체크한다. |
@Future | java.util.Date, java.util.Calendar | 해당 속성의 값이 현재일 이후인지 체크한다. |
@Max | BigDecimal, BigInteger, String, byte, short, int, long and primitive type에 대한 wrappers | 해당 속성이 가질 수 있는 최대 Length를 체크한다. |
@Min | BigDecimal, BigInteger, String, byte, short, int, long and primitive type에 대한 wrappers | 해당 속성이 가질 수 있는 최소 Length를 체크한다. |
@NotNull | any type | 해당 속성의 값이 Null이 아닌지 체크한다. |
@Null | any type | 해당 속성의 값이 Null인지 체크한다. |
@Past | java.util.Date, java.util.Calendar | 해당 속성의 값이 현재일 이전인지 체크한다. |
@Pattern | String | 해당 속성의 값이 정의된 Regular Expression에 부합하는지 체크한다. Regular Expression은 Java Regular Expression Convention (see java.util.regex.Pattern)에 맞게 정의해야 한다. |
@Size | String, Collection, Map and arrays | 해당 속성이 가질 수 있는 최대, 최소 Length를 체크한다. |
@Valid | any non primitive type | 해당 객체에 대해 Validation Check가 이루어진다. |
다음은 Foundation Plugin 설치로 추가된 도메인 클래스 ~/domain/Movie.java의 일부로써 앞서 언급한 JSR-303 Annotation을 활용하여 Validation Constraint를 정의하고 있다. 예를 들어, title 속성은 Null 값을 가질 수 없으며 최소 1자리, 최대 50자리까지만 허용하며 runtime 속성값은 최대 180을 초과할 수 없고 정수부 3자리 소수부는 0자리를 허용하고 있음을 알 수 있다.
public class Movie implements Serializable { private static final long serialVersionUID = 1L; private String movieId; @NotNull @Size(min = 1, max = 50) private String title = ""; @NotNull @Size(min = 1, max = 50) private String director; private Genre genre; @NotNull @Size(min = 5, max = 100) private String actors; @DecimalMax(value = "180") @Digits(integer=3, fraction=0) private int runtime; @DateTimeFormat(iso = ISO.DATE) @Future private Date releaseDate; @NumberFormat(pattern = "#,###") @Digits(integer=5, fraction=0) private int ticketPrice; private String posterFile; private String nowPlaying = "Y"; // getter, setter ... }
JSR-303 Spec.을 준수하는 모든 Annotation은 Annotation별 속성 외에 payload, groups, message라는 속성을 공통적으로 가진다. 각 속성이 가지는 의미에 대해 살펴보도록 하자.
payload (Programmatic Validating의 경우 활용 가능) : 사용된 Validation Constraint와 관련된 메타 정보를 정의하는데 사용된다. 특정 Constraint에 대해 payload 속성의 값으로 심각도를 정의해두면 Validation Error가 발생하였을 경우 심각도 정보를 추출할 수 있게 된다. 다음은 payload 정보가 추가 정의된 도메인 클래스의 일부로 title, director의 Validaion Constraint에 대해 Severity라는 클래스의 Error와 Warning 클래스로써 payload 값을 부여하고 있음을 알 수 있다.
public class Movie implements Serializable { private static final long serialVersionUID = 1L; private String movieId; @NotNull(payload = Severity.Error.class) @Size(min = 1, max = 50, payload = Severity.Warning.class) private String title = ""; @NotNull(payload = Severity.Error.class) @Size(min = 1, max = 50, payload = Severity.Warning.class) private String director; // ... }
다음은 위에서 언급한 Severity 클래스의 모습이다. 내부에 Warning, Error라는 클래스 정의를 포함하고 있으며 이들 각각은 javax.validation.Payload를 상속받고 있음에 유의해야 한다.
public class Severity { public static interface Warning extends Payload { }; public static interface Error extends Payload { }; }
위와 같이 코드가 구성된 경우 Validation Error를 담고 있는 ConstraintViolation 객체의 getConstraintDescriptor().getPayload() 메소드를 호출함으로써 Payload 정보를 추출할 수 있다.
Set<ConstraintViolation<Movie>> constraintViolations = validator.validate(movie); System.out.println("the number of constraint violation is " + constraintViolations.size()); Iterator<ConstraintViolation<Movie>> iterator = constraintViolations.iterator(); while (iterator.hasNext()) { ConstraintViolation<Movie> constraintViolation = iterator.next(); Set payloads = constraintViolation.getConstraintDescriptor().getPayload(); // ... }
위에서 언급한 payload 샘플 코드는 본 섹션 내의 다운로드 - anyframe.sample.validation. payload를 통해 다운로드받을 수 있다.
groups (Programmatic Validating의 경우 활용 가능) : 사용된 Validation Constraint의 그룹 정보를 정의하는데 사용된다. 일부 Constraint에 대해 동일한 그룹을 부여하게 되면 특정 그룹에 대해서만 Validation 작업을 수행할 수 있게 된다. 예를 들어, 특정 도메인 객체가 생성되는 시점의 Validation Check 대상 속성들과 해당 도메인 객체가 수정되는 시점의 Validation Check 대상 속성들이 다를 수 있기 때문에 이들에 대해 그룹을 부여하고 그룹별로 Validation을 수행하고자 하는 경우 활용할 수 있다. 다음은 groups 정보가 추가 정의된 도메인 클래스의 일부로 title, director, actors에 대해서는 Draft, Playing이라는 그룹을 부여하고 runtime, releaseDate, ticketPrice에 대해서는 Playing이라는 그룹만 부여하고 있음을 알 수 있다.
public class Movie implements Serializable { private static final long serialVersionUID = 1L; private String movieId; @NotNull(groups = { Draft.class, Playing.class }) @Size(min = 1, max = 50, groups = { Draft.class, Playing.class }) private String title = ""; @NotNull(groups = { Draft.class, Playing.class }) @Size(min = 1, max = 50, groups = { Draft.class, Playing.class }) private String director; @NotNull(groups = { Draft.class, Playing.class }) @Size(min = 5, max = 100, groups = { Draft.class, Playing.class }) private String actors; @DecimalMax(value = "180", groups = Playing.class) @Digits(integer = 3, fraction = 0, groups = Playing.class) private int runtime; @Future(groups = Playing.class) private Date releaseDate; @Digits(integer = 5, fraction = 0, groups = Playing.class) private int ticketPrice; // ... }
즉, 영화가 등록될 당시(Draft Group)에는 title, director, actors에 대해서만 Validation Check가 이루어지고 영화 상영이 결정된 이후(Playing Group)부터는 runtime, releaseDate, ticketPrice에 대해서도 추가적으로 Validation Check가 이루어질 수 있도록 하기 위함이다.
다음은 위에서 groups 정의시 활용한 Draft.java 클래스의 모습이다. group 클래스는 javax.validation.groups.Default 유형이어야 하며, group 클래스 사이에서 계층 관계를 가질 수 있다. 그리고 하위 계층 그룹에 대해 Validation Check 요청이 있을 경우 상위 계층에 대한 Validation Check도 함께 이루어지게 된다. groups 속성값이 정의되지 않은 경우 Default group으로 간주된다.
public interface Draft extends Default { }
위와 같이 코드가 구성된 경우 Validator의 validate() 메소드 호출시 group 정보를 인자로 전달하면 해당 group에 속한 속성 정보에 대해서만 Validation Check가 수행된다.
Set<ConstraintViolation<Movie>> constraintViolations = validator.validate(movie, Draft.class); System.out.println("the number of constraint violation is " + constraintViolations.size()); Iterator<ConstraintViolation<Movie>> iterator = constraintViolations.iterator(); while (iterator.hasNext()) { ConstraintViolation<Movie> constraintViolation = iterator.next(); // ... }
위에서 언급한 groups 샘플 코드는 본 섹션 내의 다운로드 - anyframe.sample.validation. groups를 통해 다운로드받을 수 있다.
message : Validation Error가 발생하였을 경우 표현되는 메시지를 정의하는데 사용된다. 기본적으로 사용중인 Validator를 포함하는 라이브러리 내에 포함된 메시지 리소스 파일로부터 해당 Annotation의 {fully-qualified class name}.message에 해당하는 메시지 값을 추출하게 된다. 예를 들어, @NotNull Check시 에러가 발생하면 javax.validation.constraints.NotNull.message에 해당하는 메시지가 표현될 것이다. 기본적으로 제공되는 메시지가 아닌 다른 메시지를 표현해주고 싶을 경우에는 message의 속성값으로 신규 메시지 key를 정의하면 된다. 그리고 클래스패스 상위에 해당 key와 이에 대한 메시지를 포함하고 있는 메시지 리소스 파일을 정의한다.
메시지 리소스 파일에 대해서는 기본적으로 국제화가 지원되며, Hibernate Validator의 경우 기본적으로 영어,불어,독일어 형태의 메시지 리소스 번들을 제공하고 있는데 만일 다른 언어로 구성된 메시지 리소스 파일을 추가하고자 원한다면 클래스패스 내에 org/hibernate/validator/ValidationMessages_{locale}.properties 파일을 추가하고 JSR-303 Annotation 각각에 대한 메시지를 정의하도록 한다.
JSR-303에서 기본적으로 제공하는 Annotation만으로 특정 도메인 클래스의 속성값에 대한 Validation Check가 수행되기 어려운 경우 프로젝트에 적합한 Custom Constraints를 정의할 수 있다. Custom Constraints를 활용하기 위해서는 Custom Annotation과 Custom Validator 구현이 이루어져야 한다. 다음은 전화번호 속성에 대한 Validation Check를 위해 신규 정의한 Telephone.java 클래스의 일부이다.
@Target( { ElementType.METHOD, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = TelephoneValidator.class) @Size(min = 12, max = 13) public @interface Telephone { String message() default "{anyframe.sample.validation.constraint.Telephone.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
위 코드에 의하면 @Telephone은 Method, Field에 대해 정의 가능하며 런타임시에 적용된다. 그리고 도메인 클래스 내에 @Telephone이 부여된 속성을 만나면 TelephoneValidator가 초기화되어 Validation Check를 수행할 것이다. 또한 @Size Annotation 정의가 추가되어 있어서 @Telephone은 기본적으로 Size에 대해서도 제약하게 된다. @Telephone은 JSR-303 Spec.에서 정의한 기본 속성(message, groups, payload) 외에 추가 속성을 포함하고 있지는 않다.
message 속성의 경우 기본값을 anyframe.sample.validation.constraint.Telephone.message으로 정의하고 있으므로 @Telephone에 대한 Validation Check 관련 Error가 발생한 경우 클래스패스 최상위의 ValidationMessages.properties 파일로부터 anyframe.sample.validation.constraint.Telephone.message을 key로 하는 메시지가 출력될 것이다. 다음은 ValidationMessages.properties 파일의 내용이다.
anyframe.sample.validation.constraint.Telephone.message=must match "0000-000(or 0000)-0000" (max 13)
다음은 @Telephone Annotation에 대해 Validation Check를 수행할 TelephoneValidator.java 파일의 일부이다. 다음 코드에서와 같이 Custom Validator는 javax.validation.ConstraintValidator 인터페이스를 implements해야 하며 Validation Check 로직을 수행할 isValid()라는 메소드를 구현해주어야 한다.
public class TelephoneValidator implements ConstraintValidator<Telephone, String> { private java.util.regex.Pattern pattern = java.util.regex.Pattern .compile("^[0-9]\\d{2}-(\\d{3}|\\d{4})-\\d{4}$"); public void initialize(Telephone annotation) { } public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null || value.length() == 0) { return true; } Matcher m = pattern.matcher(value); return m.matches(); } }
TelephoneValidator는 Regular Expression을 이용하여 전화번호에 대한 패턴을 정의해 두고 이 패턴과 동일하지 않을 경우 Validation Error를 발생하게 된다.
다음은 앞서 정의한 @Telephone 정의를 포함하고 있는 도메인 클래스 Movie.java 파일의 일부이다.
public class Movie implements Serializable {
private static final long serialVersionUID = 1L;
private String movieId;
@Telephone
private String telephone;
// ...
}
위에서 언급한 Custom Constraint 샘플 코드는 본 섹션 내의 다운로드 - anyframe.sample.validation. custom를 통해 다운로드받을 수 있다.
Spring MVC 2.5 이전에서는 앞서 언급한 바와 같이 Spring Validator를 구현하고 이를 특정 Controller의 Validator로 직접 지정해 주어야만 Validation Check가 이루어졌었다. 그러나 Spring 3 이후부터는 Controller 메소드의 입력 인자에 대해 @Valid라는 Annotation을 부여함으로써 해당 메소드 호출 전에 자동적으로 Validation Check가 이루어질 수 있도록 지원한다. 다음은 Foundation Plugin 설치로 추가된 ~/foundation/moviefinder/web/MovieController.java 클래스 내에 정의된 create() 메소드의 일부이다.
@RequestMapping(params = "method=create")
public String create(..., @Valid Movie movie, BindingResult results, ...) throws Exception {
if (results.hasErrors()) {
return "foundationViewMovie";
}
// ...
}
위 메소드의 경우, 사용자의 입력값을 Movie 객체로 매핑할 때 Validation Check가 이루어지게 되고 결과값은 BindingResult 객체에 담겨지게 된다. 따라서 입력 인자로 전달된 BindingResult 객체 내에 Validation Error가 존재하는 경우 입력 화면으로 되돌아가도록 로직을 구성하면 된다.
또한 Spring에서 제공하는 <form:errors>를 활용하면 Validation Error를 입력 화면에 표현해 줄 수 있게 된다. 다음은 Foundation Plugin 설치로 추가된 webapp/WEB-INF/jsp/foundation/moviefinder/movie/form.jsp 파일의 일부로 title, director 필드에 입력된 값이 유효하지 않을 경우 <form:errors>를 이용하여 표현해 줄 수 있도록 정의하고 있음을 알 수 있다.
<tr> <td width="150" class="ct_td"><spring:message code="movie.title" /> *</td> <td bgcolor="D6D6D6" width="1"></td> <td class="ct_write01"> <form:input path="title" cssClass="ct_input_g" cssErrorClass="text medium error" size="40" maxlength="50" /> <form:errors path="title" cssClass="errors" /> </td> </tr> <tr> <td height="1" colspan="3" bgcolor="D6D6D6"></td> </tr> <tr> <td width="150" class="ct_td"><spring:message code="movie.director" /> *</td> <td bgcolor="D6D6D6" width="1"></td> <td class="ct_write01"> <form:input path="director" cssClass="ct_input_g" cssErrorClass="text medium error" size="40" maxlength="50" /> <form:errors path="director" cssClass="errors" /> </td> </tr>
끝으로 선언적인 Validation Check를 위해서는 Validator 지정을 위한 속성 정의가 필요하다. Spring에서는 이를 위해 3가지 방법을 제공한다.
Spring 3에서 새롭게 선보이는 mvc namespace를 활용하는 것으로 다음과 같이 정의된 경우 클래스패스로부터 Hibernate Validator와 같은 JSR-303 Validator 구현체가 자동으로 검색되어 모든 @Controller에 적용된다.
<mvc:annotation-driven />
Spring 3에서 새롭게 선보이는 mvc namespace를 활용하되 특정 Validator를 지정하는 것으로 지정된 Validator가 모든 @Controller에 적용된다.
<mvc:annotation-driven validator="..."/>
Controller 클래스 내에 @InitBinder 메소드를 정의하고 해당 메소드의 입력 인자로 전달된 Binder에 특정 Validator를 셋팅하는 것으로, 이 경우 셋팅된 Validator가 특정 Controller에만 적용된다.
@Controller public class MovieController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.setValidator(new CustomValidator()); } // ... }
Spring에서는 Validation Check가 필요한 경우에 Hibernate Validator와 같은 JSR-303 Validator 구현체를 실행시킬 수 있도록 하기 위해 LocalValidatorFactoryBean 클래스를 제공한다. LocalValidatorFactoryBean은 클래스패스 내에 JSR-303 구현체와 관련된 라이브러리를 검색하여 Validator를 자동으로 검색해주는 역할을 수행한다. 따라서 LocalValidatorFactoryBean을 Bean으로 정의하고 특정 클래스에서 이 Bean을 참조하여 Validation Check를 수행하면 된다.
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
@Service
public class MovieServiceImpl implements MovieService {
/**Inject a reference to javax.validation.Validator if you prefer to work with the JSR-303 API directly.
* Inject a reference to org.springframework.validation.Validator if your bean requires the Spring Validation API
*/
@Inject
private Validator validator;
public void create(Movie movie){
validator.validate(movie);
// ...
}
}
다운로드
다음에서 sample 코드를 포함하고 있는 Eclipse 프로젝트 파일을 다운받은 후, 압축을 해제한다.
Maven 기반 실행
Command 창에서 압축 해제 폴더로 이동한 후, mvn compile exec:java -Dexec.mainClass=...이라는 명령어를 실행시켜 결과를 확인한다. 각 Eclipse 프로젝트 내에 포함된 Main 클래스의 JavaDoc을 참고하도록 한다.
Eclipse 기반 실행
Eclipse에서 압축 해제 프로젝트를 import한 후, src/main/java 폴더 하위의 Main.java를 선택하고 마우스 오른쪽 버튼 클릭하여 컨텍스트 메뉴에서 Run As > Java Application을 클릭한다. 그리고 실행 결과를 확인한다.
출처 - http://dev.anyframejava.org/docs/anyframe/plugin/foundation/4.6.1/reference/html/ch13.html
스프링 MVC에서 지원하는 @Valid를 통한 데이터 검증은 정말 놀랍다. 특히 브라우저에서 클라이언트가 입력자료를 넘겨줄 때 이 자료를 검증할 수 있는 모델을 매우 손쉽게 만들 수 있다는 점이다. @Valid는 스프링이 만든 기술은 아니며 최근 JSR-303이란 이름으로 채택된 서블릿 2.3 표준스펙 중 하나인데 매번 그렇듯 스프링은 이 새로운 표준을 확장하고 쉽게 사용할 수 있도록 스프링만의 방식으로 재편성해주었다.
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 생략 …
}
@AssertFalse : false 값만 통과 가능
@AssertTrue : true 값만 통과 가능
@DecimalMax(value=) : 지정된 값 이하의 실수만 통과 가능
@DecimalMin(value=) : 지정된 값 이상의 실수만 통과 가능
@Digits(integer=,fraction=) : 대상 수가 지정된 정수와 소수 자리수보다 적을 경우 통과 가능
@Future : 대상 날짜가 현재보다 미래일 경우만 통과 가능
@Past : 대상 날짜가 현재보다 과거일 경우만 통과 가능
@Max(value) : 지정된 값보다 아래일 경우만 통과 가능
@Min(value) : 지정된 값보다 이상일 경우만 통과 가능
@NotNull : null 값이 아닐 경우만 통과 가능
@Null : null일 겨우만 통과 가능
@Pattern(regexp=, flag=) : 해당 정규식을 만족할 경우만 통과 가능
@Size(min=, max=) : 문자열 또는 배열이 지정된 값 사이일 경우 통과 가능
@Valid : 대상 객체의 확인 조건을 만족할 경우 통과 가능
<%@ 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>
@Size(min=5, max=50, message="5자에서 50자 사이의 값만 가능합니다") private String id;
출처 - http://springmvc.egloos.com/509029
Spring3.0 에서 Validation 기능을 보면 이전 버전
에서 사용했던 Validation 방법 뿐만 아니라
새로운 기능들이 추가가 되었습니다.
그중에서 단연 꽃은 JSR-303 스펙 입니다.
혹자는 이것을 Spring 3.0 Validation이라고 합니다.
JSR-303스펙은 쉽게 말해서 자바의 모든 클래스 자체에
검증 로직을 annotation으로 설정 해서 검증이
필요한 어느 곳이든 해당 검증을 수행 할 수 있도록
하는 J2EE Spec 입니다.
ㅋㅋ 저 답지 않게 유식한 척을 했군요
아래 코드를 보면서 간략 하게 설명 드리겠습니다.
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
위에 코드를 보면 name 속성은 반드시 값이 존재 해야 하고,
length는 64자를 넘어서는 안된 다는 것입니다.
이렇게 클래스에 검증 로직을 넣고 검증이 필요한 곳
에서 실행을 하면 됩니다.
* Library 설정
먼저 Spring 3.0 에서 JSR-303 스펙을 구현 하기 위해서는
아래의 라이브러리가 필요 합니다.
(1) jax-validation.jar (JSR-303 스펙 라이브러리)
(2) hibernate-validation.jar (JSR-303 구현체 라이브러리)
위 의 두개의 라이브러리를 다운 받아서 이클립스 classpath
를 설정 합니다.
만약 Maven을 사용 하시는 분들은 아래의 pom.xml을
추가 합니다.
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.com/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.0.Beta2</version>
</dependency>
</dependencies>
스프링 3.0 full pom.xml 설정을 원하 시는 분들은
제 블러그 “Spring3.0 관련 라이브러리 (pom.xml)”
을 참조 하시면 됩니다.
* 검증 클래스 작성
package org.springshowcase.mvc;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validation.constraints.NotEmpty;
public class User {
@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp=”[0-9a-zA-Z]”)
private String id;
@NotEmpty()
private String name;
@NotEmail
private String email;
private Integer age;
…setter & getter method
}
위의 소스를 보면 전형적인 일반 자바 빈즈
클래스 형태 입니다.
“id” 속성의 검증 로직은 아래와 같습니다.
- 반드시 값이 존재 해야함
- 반드시 길이는 1이상 5이하여야 함 (byte 기준 아님)
- 반드시 영문 또는 숫자 형태여야함
“email” 속성에서 “@NotEmail”은 제가 직접
만든 annotation입니다. 이부분은 뒤에서
설명 하도록 하겠습니다.
* Spring 빈 설정
스프링에서 JSR-303 스펙을 적용 하기 위해서는
다소 복잡한 과정을 거쳐야 합니다.
“LocalValidatorFactoryBean” 빈을 설정 하고 또 이 빈을
“AnnotationMethodHandlerAdapter” 선언된 빈에
injection 해야 하고…
이런거 필요 없이 spring3.0 에서 아주 간단한
네임스페이스를 제공 합니다.
<mvc:annotation-driven />
위와 같이 선언 하면 스프링에서 JSR-303 적용은
끝입니다.
Comming Up Next…
- Controller에서 Validation 사용 하는 방법
- JSR-303 기반 Message 번들 적용 방법
- JSP 설정 방법
- 커스컴 Validation Annotation 작성 방법
- Spring Validation VS JSR 303
“Spring 3.0 Validation Part1“에 이어서 설명 드리도록 하겠습니다.
먼저 이전에 작성한 User 도메인 클래스 입니다.
package org.springshowcase.mvc;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validation.constraints.NotEmpty;
public class User {
@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp="[0-9a-zA-Z]")
private String id;
@NotEmpty()
private String name;
@NotEmail
private String email;
private Integer age;
...setter & getter method
}
* Controller에서 Validation 사용 하는 방법
Controller 에서 사용 하는 방법은 의외로 간단 합니다.
@RequestMapping(method = RequestMethod.POST)
public ModelAndView processSubmit(@Valid @ModelAttribute("user") User user,
BindingResult result, SessionStatus status) {
ModelAndView mav = new ModelAndView();
if (result.hasErrors()) {
System.out.println(".....invalid");
}
return mav;
}
위의 소스를 보면 검증을 위해서 파라미터 부분에
“@Valid” 어노테이션을 설정하면 끝입니다.
즉 저말은 User 도메인에 검증 로직을 실행 하라
는 뜻입니다. 이미 검증이 끝났기 때문에
“result.hasErrors”를 통해서 validation
분기 로직을 적절하게 작성 하면 됩니다.
* JSP 설정 방법
<form:input path="id" /> <br />
<font color="yellow"><form:errors path="id" /></font><br />
<label for="contact_email">Enter user name: </label> <br />
<form:input path="name" /><br />
<font color="yellow"><form:errors path="name" /></font><br />
<label for="contact_email">Enter email: </label> <br />
<form:input path="email" /><br />
<font color="yellow"><form:errors path="email" /></font><br />
<label for="contact_subject">Enter Age: </label> <br />
<form:input path="age" /> <br /><br />
<input type="button" value="Save Changes" onclick="doSave();" class="button" />
</form:form>
JSP 소스는 이전 버전과 동일 하게 위와 같이 코드를
작성 합니다.
* Invalid시 Message 리소스 적용 하기
이 부분은 SpringSource 팀 블러그와 JSR-303 스펙을
보면서 알아낸 방법 입니다.매우 중요한 부분이니
잘 이해하시기 바랍니다.
먼저 아래와 같이 메세지 번들을 설정 합니다.
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages.default</value>
</list>
</property>
</bean>
default_ko.properties
메세지 expression은 “검증 annotation명+도메인명+속성명”
으로 하며 key 작성 규칙은 java method 형식으로
합니다.
NotEmpty.user.id=아이디를 입력 하세요.
Size.user.id=아이디는 5자 이하 입니다.
Pattern.user.id=아이디는 반드시 영문 또는 숫자만 입력 가능 합니다.
NotEmpty.user.name=이름을 입력 하세요.
NotEmail.user.email=이메일 형식이 틀립니다.
public class User {
@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp="[0-9a-zA-Z]")
private String id;
.....
}
예를 들어서 “@NotEmpty”의 경우 메세지 키는
NotEmpty(annotation 명) + “.” + user(도메인 클래스명)
+”.” + id(속성명) 그래서 전체 메세지 키는
“NotEmpty.user.id”가 되는 것입니다.
Part3에서는 Custom Validation 작성 방법에
대해서 말씀을 드리겠습니다.
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”를 체크아웃
받으시면 됩니다.
자세한 내용은 오픈 소스 사이트를 참고 하시기 바랍니다.
출처 - http://beyondj2ee.tumblr.com/post/14509177207/spring-3-0-validation-part3
In this example application we will be create a Validation form in Spring 3.0 MVC Framework. The validation of the form is done using annotation. The Hibernate validator framework is used for validation of the form data.
The application will present simple user registration form to the user. Form will have the following fields:
- User Name
- Age
- Password
The validator framework will validate the user input. If there is any validation error application will display the appropriate message on the form.
To use the validation framework in the application "hibernate-validator-4.0.2.GA.jar" and " validation-api-1.0.0.GA.jar" must be added to the project libraries.
Application uses following jar files:
Step 1:
Create index.jsp under WebContent . The code index.jsp as :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Spring 3, MVC Examples</title> </head> <body> <h1>Spring 3, MVC Examples</h1> <ul> <li><a href="forms/validationform.html">Validation Form</a></li> </ul> </body> </html> |
In the above page we are creating a new link to access the Validation Form example from the index page of the application.
Step 2:
Now we will create a model class " ValidationForm.java" under src folder . The code of "ValidationForm.java" is:
package net.roseindia.form;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.format.annotation.NumberFormat.Style;
public class ValidationForm {
@NotEmpty
@Size(min = 1, max = 20)private String userName;
@NotNull
@NumberFormat(style = Style.NUMBER)
@Min(1)
@Max(110)
private Integer age;
@NotEmpty(message = "Password must not be blank.")
@Size(min = 1, max = 10, message = "Password must between 1 to 10 Characters.")
private String password;
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
In the above class we have added the proper annotation for validating the form values. Here is the list of annotation used for validation:
@NotEmpty
@Size(min = 1, max = 20)
@NotNull
@NumberFormat(style = Style.NUMBER)
@Min(1)
@Max(110)
@NotEmpty(message = "Password must not be blank.")
@Size(min = 1, max = 10, message = "Password must between 1 to 10 Characters.")
Step 3 :
Now create a folder views under WebContent/WEB-INF . Again cerate "validationform.jsp" under WebContent/WEB-INF/views as :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <form:form method="post" action="validationform.html" commandName="validationForm"> <table> <tr> <td>User Name:<font color="red"><form:errors path="userName" /></font></td> </tr> <tr> <td><form:input path="userName" /></td> </tr> <tr> <td>Age:<font color="red"><form:errors path="age" /></font></td> </tr> <tr> <td><form:input path="age" /></td> </tr> <tr> <td>Password:<font color="red"><form:errors path="password" /></font></td> </tr> <tr> <td><form:password path="password" /></td> </tr> <tr> <td><input type="submit" value="Submit" /></td> </tr> </table> </form:form> </body> </html> |
In this above jsp file <form:errors path="..." /> tag is used to display the validation error messages.
Step 4:
Now create "validationsuccess.jsp" file under WebContent/WEB-INF/views . The code of "validationsuccess.jsp" is :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <core:out value="${validationForm.userName}" /> Save Successfully. </body> </html> |
Step 5:
Now create Contoller class "ValidationController.java" under src folder. Controller class use for RequestMapping and process the user request. The code of "ValidationController.java" as:
package net.roseindia.controllers;
import net.roseindia.form.ValidationForm;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/validationform.html")
public class ValidationController {
// Display the form on the get request
@RequestMapping(method = RequestMethod.GET)
public String showValidatinForm(Map model) {
ValidationForm validationForm = new ValidationForm();
model.put("validationForm", validationForm);
return "validationform";
}
// Process the form.
@RequestMapping(method = RequestMethod.POST)
public String processValidatinForm(@Valid ValidationForm validationForm,
BindingResult result, Map model) {
if (result.hasErrors()) {
return "validationform";
}
// Add the saved validationForm to the model
model.put("validationForm", validationForm);
return "validationsuccess";
}
}
The @RequestMapping annotation is used for request uri mapping.
Step 6:
Now modify web.xml as:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"> <display-name>Spring3Example</display-name> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/forms/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> |
Step 7:
Again create "dispatcher-servlet.xml" under WebContent/WEB-INF . The "dispatcher-servlet.xml" code as :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd "> <!-- Enable annotation driven controllers, validation etc... --> <mvc:annotation-driven /> <context:component-scan base-package="net.roseindia.controllers"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/views/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> <bean id="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/messages" /> </bean> </beans> |
Where <mvc:annotation-driven> is used for annotation driven controllers and validation. While message Resource configuration is done in "dispatcher-servlet.xml" using following entry:
<bean id="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/messages" /> </bean> |
Again create customization Message file "messages.properties" under WebContent/WEB-INF. The modify "messages.properties" as
NotEmpty.validationForm.userName=User Name must not be blank. Size.validationForm.userName=User Name must between 1 to 20 characters. |
Step 8:
Now run Application display output as :
if click Validation Form hyperlink then open validationform as :
Step 9:
Now Enter userName, Age and Password if find any error display as:
Again display error-
If validation success then display validationsucess page as :
In this we have studies the use of annotation controller and annotated validators.
출처 - http://sway.tistory.com/entry/Spring-3-MVC-Validation-Example
org.springframework.validation.BindException 에 대한 한가지 해결 방안
아래 post에 의하면 @Valid 적용 객체 다음에 BindingResult가 바로 와야한다.
1 | I got a new roo project off the ground successfully, but now I'm having a problem getting validation to work for a login page. It seems that the validator is choking before passing control to my controller. I am never given the opportunity to check the BindingResult. I've examined several similar questions here and on the web, and my code seems to conform with what they are doing. First the error I get when submitting the form (if i pass validation i get no error message). In this case i didn't meet the minimum length for the password:
My entity validation is setup like this:
Here is my markup:
And the controller:
And just in case it matters, the generated xml in webmvc-config.xml:
Been pulling my hair out for hours and I can't figure out what it could be. Thanks for reading! | ||||
|
6 | In your controller handler method, try moving the BindingResult argument so it is immediately after the command argument. Spring looks for command object parameters and BindingResult parameters to be paired up in handler method signatures. | ||||||||
|
출처 - http://stackoverflow.com/questions/9916623/spring-valid-validator-not-invoked-properly-roo-hibernate
Email Regular Expression Pattern
^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)* @[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$;
@DateTimeFormat
(pattern=
"MM/dd/yyyy"
)
@NotNull
@Past
private
Date birthday;
'Framework & Platform > Spring' 카테고리의 다른 글
도메인 객체(오브젝트) (0) | 2012.05.21 |
---|---|
spring - @SessionAttributes 와 SessionStatus (0) | 2012.05.21 |
spring - Validator (0) | 2012.05.21 |
Spring - @ModelAttribute (0) | 2012.05.21 |
Spring - @RequestParam (0) | 2012.05.21 |