Validator 인터페이스
회원가입 혹은 게시물 작성과 같은 유효성 검증이 필요할 때,
자바스크립트를 통한 검증은 보안이 약해 서버단에서 실질적인 검증이 되지 못한다.
따라서, 확실한 검증을 위해 스프링은 Validator 인터페이스를 제공한다.
그렇기 때문에 보통 브라우저에서 검증 + Validator 인터페이스로 검증 두 가지를 함께 사용한다.
다음과 같은 회원가입 폼에 대한 유효성 검사를 진행해보자.
1. RegisterRequest : 회원가입 폼의 내용을 담을 VO 객체 생성
package spring;
public class RegisterRequest {
private String email;
private String password;
private String confirmPassword;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 입력한 두 패스워드가 일치하는지 확인하는 메서드
public boolean isPasswordEqualToConfirmPassword() {
return password.equals(confirmPassword);
}
}
2. Validator 인터페이스를 구현한 RegisterRequestValidator 클래스 작성
Validator 인터페이스에서 구현해야하는 두 가지 추상 메서드
- supports() : Validator가 해당클래스에 대한 값 검증을 지원하는지에 대한 여부 리턴
- validate() : 이것이 중요. 검증해야할 내용이 담김.
Errors 인터페이스
- 유효성 검증 결과를 저장할 때 사용
- 메서드 종류
reject(String errorCode) : 전 객체에 대한 글로벌 에러 코드를 추가
rejectValue(String field, String errorCode) : 필드에 대한 에러코드를 추가
ValidationUtils 클래스
- 유효성 검증을 도와주는 클래스
- rejectIfEmpty() : 값이 null이거나 길이가 0인 경우 에러 코드를 추가
- rejectIfEmptyOrWhitespace() : 값이 null이거나 길이가 0이거나 값이 공백 문자로 구성되어 있는 경우 에러 코드를 추가
Pattern 클래스
- 정규식을 사용하기 위한 클래스 ( + Matcher 클래스)
- matches() : 패턴이 전체 문자열과 일치할 경우 true 반환
// compile(): 패턴 생성
Pattern pattern = Pattern.compile("\\+\\d{2}-\\d{2}-\\d{4}-\\d{4}");
// matcher(): 매치된 결과물 저장
Matcher match = pattern.matcher(phone_number);
// matches(): 결과물이 패턴과 일치하냐? 일치하면 true, 불일치하면 false 반환
boolean right = match.matches();
package spring;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class RegisterRequestValidator implements Validator {
// 이메일 관련 정규 표현식
private static final String EMAIL_REG_EXP =
"^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9]+)*@"
+ "[A-Za-z0-9]+(\\.[_A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
private Pattern pattern;
// 생성자
public RegisterRequestValidator() {
pattern = Pattern.compile(EMAIL_REG_EXP);
}
// 첫 번째 추상 메서드 supports()
// 자동으로 검증할 때 사용한다고 한다. 일단 비워놓을 수 없으니 이렇게 셋팅해두자.
@Override
public boolean supports(Class<?> clazz) {
return RegisterRequest.class.isAssignableFrom(clazz);
}
// 두 번째 추상 메서드 validate()
// 이 메서드를 호출해서 커맨드 객체들의 값이 유효한지 검증
@Override
public void validate(Object target, Errors errors) {
// target : 검사 대상 객체 참조 (커맨드 객체)
// errors : target 검사 후, 에러 코드를 저장하는 객체 (스프링이 만들어서 전달해 준 것)
RegisterRequest regReq = (RegisterRequest) target;
// 이메일 유효성 검증
if(regReq.getEmail() == null || regReq.getEmail().trim().isEmpty()) {
// errors.rejectValue(): 어떤 필드가 잘못되었는지, 관련된 에러가 무엇인지 입력받음
errors.rejectValue("email", "required"); // (필드명, 에러코드)
} else {
// email에 어떠한 값이 들어온다면 일단 matcher에 저장
Matcher matcher = pattern.matcher(regReq.getEmail());
if(!matcher.matches()) { // 그 값이 정규표현식과 매치가 안되냐?
errors.rejectValue("email", "bad");
}
}
// 이름 유효성 검증
// ValidationUtils는 에러 검증을 편하게 할 수 있도록 메서드를 지원
// rejectIfEmptyOrWhitespace: 값이 없거나 공백이 있는가?
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required");
// 비밀번호 유효성 검증
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "required");
// 비밀번호 확인 유효성 검증
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword", "required");
// 비밀번호와 비밀번호 확인을 비교하여 유효성 검증
if(!regReq.getPassword().isEmpty()) { // 값이 비어있지 않다면
if(!regReq.isPasswordEqualToConfirmPassword()) { // 일치하지 않는다면
errors.rejectValue("confirmPassword", "nomatch"); // 에러 발생
}
}
}
}
3. RegisterController 클래스 작성
// 커맨드 객체 활용
@RequestMapping(value = "/register/step3", method = RequestMethod.POST)
public String handleStep3(@ModelAttribute("formData") RegisterRequest regReq,
Errors errors) { // 에러를 담기 위한 객체는 반드시 커맨드 객체 선언 바로 뒤에 위치! 꼭!
// 커맨드 객체 검증 요청: .validate() -> 검증해주세요
new RegisterRequestValidator().validate(regReq, errors);
if(errors.hasErrors()) { // RegisterRequestValidator 검사했더니 에러가 있었니?
return "register/step2";
}
try {
memberRegSvc.regist(regReq); // 이상 없으면
return "register/step3"; // 회원가입 완료 페이지로 넘어가
} catch(AlreadyExistingMemberException e) { // 이미 회원이 있을 경우
errors.rejectValue("email", "duplicate"); // 이메일 중복 에러 추가
return "register/step2"; // 다시 회원가입 페이지로 돌아가
}
}
4. step2.jsp 작성
<form:errors path="email" element="div"/>에서
element="div"로 설정하면 바로 아래에 에러 문구가 추가되고,
디폴트로 설정해두면 span으로 설정된다.
그 밖에 다른 영역에 설정하고 싶다면 다양한 속성이 있으니 골라쓰길~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><spring:message code="member.register"/></title>
</head>
<body>
<h2><spring:message code="member.info"/></h2>
<form:form action="step3" commandName="formData">
<p>
<label><spring:message code="email"/>
<form:input path="email"/>
<!-- 에러를 표시하기 위한 위치 -->
<form:errors path="email" element= "div"/></label>
</p>
<p>
<label><spring:message code="name"/>
<form:input path="name"/>
<form:errors path="name"/></label>
</p>
<p>
<label><spring:message code="password"/>
<form:password path="password"/>
<form:errors path="password"/></label>
</p>
<p>
<label><spring:message code="password.confirm"/>
<form:password path="confirmPassword"/>
<form:errors path="confirmPassword"/></label>
</p>
<input type="submit" value="<spring:message code="register.btn"/>">
</form:form>
</body>
</html>
5.messageSource 사용한 properties 파일에 추가
메세지 검색 우선 순위
에러코드.모델이름.필드이름: required.registerRequest.email
에러코드.필드이름: required.email -> 보통 이렇게 사용
에러코드.타입이름: required.String -> 거의 안씀!!
에러코드: required -> 가장 낮은 우선 순위이나, 다양한 곳에 적용되어야할 때, 주로 사용
bad.email=이메일 형식이 올바르지 않습니다.
required.email=이메일은 필수입니다.
required=필수 항목 입니다. // 가장 낮은 우선 순위
duplicate.email=중복된 이메일입니다.
nomatch.confirmPassword=비밀번호를 확인해주세요.
'SPRING' 카테고리의 다른 글
@RequestParam 어노테이션 (0) | 2020.10.11 |
---|---|
Lombok / Junit 라이브러리 (0) | 2020.10.10 |
MessageSource 설정하기 (0) | 2020.10.07 |
간단한 페이지 이동 <mvc:view-controller> (0) | 2020.10.07 |
스프링에서 커맨드 객체 활용하기 (0) | 2020.10.07 |