폼에서 입력한 값을 클라이언트 측에서는 자바스크립트를 사용해서 유효성을 검증하고 서버측에서도 검증을 하여야 합니다. 서버측에서 폼에 입력된 값을 검정하는데 사용되어질 수 있는 Hibernate Bean Validator 를 사용하는 방법을 알아봅니다.
1. pom.xml 파일에 의존성을 추가합니다.
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.8.Final</version>
</dependency>
2. 메세지 다국어 처리
- 기본적인 다국어 설정은 "Spring Framework 메세지 국제화(다국어 지원) 사용하기"를 참조하세요.
- root-context.xml 파일에 Validator가 messageSource를 사용하도록 설정합니다.
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource" />
</bean>
- servlet-context.xml 파일에 Controller가 앞에서 설정한 validator를 사용하도록 설정합니다.
<annotation-driven validator="validator"/>
3. Form 작성하기(boardRegisterForm.jsp)
<c:url var="insertUrl" value="/boardInsert.do" />
<form:form commandName="boardVO" action="${insertUrl}" name="boardVO" method="post">
<form:errors path="*" cssClass="error" />
<table border="1">
<tr>
<th>이름</th>
<td>
<form:input path="name" id="name" size="20" maxlength="20" />
<form:errors path="name" cssClass="error" />
</td>
</tr>
<tr>
<th>비밀번호</th>
<td>
<form:password path="password" id="password" size="20" maxlength="20" />
<form:errors path="password" cssClass="error" />
</td>
</tr>
...
</table>
</form:form>
- <form:errors path="*" cssClass="error" />를 사용해서 전체 에러 메세지를 출력할 수 있습니다.
- <form:errors path="name" cssClass="error" /> 부분에 개별 에러 메세지가 출력됩니다.
4. VO에 제약사항 지정하기(BoardVO.java)
@Size(min=2, message="{board.name}")
private String name; /* 이름 */
@Size(min=8, message="비밀번호는 8자 이상이어야 합니다.")
private String password; /* 비밀번호 */
@Size(min=5, message="이메일 형식이 아닙니다.")
@Email(message="이메일 형식이 아닙니다.")
private String email; /* 이메일 */
- VO객체의 멤버변수에 아노테이션을 사용해서 제약사항을 부여합니다.
- message 부분에 {board.name} 은 다국어 지원으로 messageSource에서 값을 가져옵니다.
5. 내장되어 있는 제약사항
아노테이션 | 설명 / 지원 데이터 타입 |
---|---|
@AssertFalse | 값이 false 인지 확인합니다. |
Boolean, boolean | |
@AssertTrue | 값이 true 인지 확인합니다. |
Boolean, boolean | |
@DecimalMax(value=, inclusive=) | 값이 inclusive=false일때 지정된 최대값 보다 작은지 확인합니다. inclusive=true 이면 값이 지정된 최대값보다 작거나 같은지 확인합니다. 매개변수 값은 BigDecimal 문자열 표현에 따라 최대값의 문자열 표현입니다. |
BigDecimal, BigInteger, CharSequence, byte, short, int, long 과 원시타입 래퍼 클래스를 지원합니다; HV에 의해 추가로 지원 : Number 와 javax.money.MonetaryAmount의 서브타입 (만약 JSR 354 API 구현이 클래스 패스에 존재한다면) | |
@DecimalMin(value=, inclusive=) | 값이 inclusive=false일때 지정된 최소값 보다 큰지 확인합니다. inclusive=true 이면 값이 지정된 최소값보다 크나 같은지 확인합니다. 매개변수 값은 BigDecimal 문자열 표현에 따라 최소값의 문자열 표현입니다. |
BigDecimal, BigInteger, CharSequence, byte, short, int, long 과 원시타입 래퍼 클래스를 지원합니다; HV에 의해 추가로 지원 : Number 와 javax.money.MonetaryAmount의 서브타입 | |
@Digits(integer=, fraction=) | 값이 integer=와 fraction=에 의해 지정된 자리수의 숫자인지 확인합니다. |
BigDecimal, BigInteger, CharSequence, byte, short, int, long 과 원시타입 래퍼 클래스를 지원합니다; HV에 의해 추가로 지원 : Number 와 javax.money.MonetaryAmount의 서브타입 | |
지정된 문자 시퀀스가 유효한 전자 메일 주소인지 여부를 확인합니다. 선택적 매개 변수 regexp 및 flags를 사용하면 전자 메일과 일치해야하는 추가 정규 표현식 (정규식 플래그 포함)을 지정할 수 있습니다. | |
CharSequence | |
@Future | 날짜가 미래인지 확인합니다. |
java.util.Date, java.util.Calendar, java.time.Instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonth, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate; HV에 의해 추가로 지원, 만약 Joda Time date/time API 가 클래스 패스에 있다면 : 모든 ReadablePartial 과 ReadableInstant의 구현 | |
@FutureOrPresent | 날짜가 현재 또는 미래인지 확인합니다. |
java.util.Date, java.util.Calendar, java.time.Instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonth, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate; HV에 의해 추가로 지원, 만약 Joda Time date/time API 가 클래스 패스에 있다면 : 모든 ReadablePartial 과 ReadableInstant의 구현 | |
@Max(value=) | 값이 지정된 최대값보다 작거나 같은지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@Min(value=) | 값이 지정된 최소값보다 크거나 같은지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@NotBlank | 값이 null이 아니고, 트림 된 길이가 0보다 큰지 확인합니다. @NotEmpty와의 차이점은 이 제약은 CharSequence에만 적용되고 트림된다는 것입니다. |
CharSequence | |
@NotEmpty | 값이 null도 빈것도 아닌지 확인합니다. |
CharSequence, Collection, Map, arrays | |
@NotNull | 값이 null이 아닌지 체크합니다. |
모든 타입 | |
@Negative | 값이 음수인지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@NegativeOrZero | 값이 음수이거나 0인지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@Null | 값이 null인지 확인합니다. |
모든 타입 | |
@Past | 값이 과거일자인지 확인합니다. |
java.util.Date, java.util.Calendar, java.time.Instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonth, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate; HV에 의해 추가로 지원, 만약 Joda Time date/time API 가 클래스 패스에 있다면 : 모든 ReadablePartial 과 ReadableInstant의 구현 | |
@PastOrPresent | 값이 과거 또는 현재인지 확인합니다. |
java.util.Date, java.util.Calendar, java.time.Instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonth, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate, java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate; HV에 의해 추가로 지원, 만약 Joda Time date/time API 가 클래스 패스에 있다면 : 모든 ReadablePartial 과 ReadableInstant의 구현 | |
@Pattern(regex=, flags=) | 주어진 플래그 매치를 고려하여 값이 정규식 regex와 일치하는지 검사합니다. |
CharSequence | |
@Positive | 값이 양수 인지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@PositiveOrZero | 값이 양수이거나 0인지 확인합니다. |
BigDecimal, BigInteger, byte, short, int, long 과 원시타입의 래퍼 클래스; HV에 의해 추가로 지원: CharSequence의 서브 타입 (문자 시퀀스로 표현된 숫자값이 평가되어집니다.), Number 와 javax.money.MonetaryAmount의 서브 타입 | |
@Size(min=, max=) | 값이 min=과 max= 사이에 있는지 확인합니다.(경계 포함) |
CharSequence, Collection, Map, arrays |
6. Validation 하기
@RequestMapping(value = "/boardInsert.do", method = RequestMethod.POST)
public String boardInsert(@Valid BoardVO boardVO, Errors errors, Model model) throws Exception {
if(errors.hasErrors()) {
return "boardRegisterForm";
}
return "redirect:/boardRegisterForm.do";
}
- 사용자가 입력한 값을 boardVO 에 자동으로 맵핑됩니다. 여기에 @Valid 아노테이션을 지정하면 유효성 검사가 이루어 집니다.
- Errors errors 는 검증한 결과를 가지고 있습니다. BindingResult 객체를 사용해도 됩니다.
- errors.hasErrors() 가 참이면 검증에서 오류가 발생한 것입니다.
7. 실행결과
※ 전체소스
'프로그래밍 > 스프링프레임워크' 카테고리의 다른 글
전자정부표준프레임워크 3.7 설치하기 (0) | 2018.04.27 |
---|---|
Hibernate Bean Validator 사용하기(2) - 그룹과 커스텀 아노테이션 (0) | 2018.04.21 |
스프링프레임워크 에러페이지 만들기 (4) | 2018.04.21 |
도메인 이전시 기존 도메인의 모든 URL을 새 도메인으로 리다이렉트하기 (0) | 2018.04.21 |
Apache PDFBox 라이브러리를 사용해서 PDF 파일 만들기 (0) | 2018.04.20 |