3. Back-end/3-2. Spring MVC - 남궁성

Spring MVC - [ 데이터의 검증 ]

yunyj99 2023. 2. 2. 23:22

1. Validator

validator란 객체를 검증하기 위한 인터페이스로, 객체 검증기(validator)구현에 사용한다.

 

아래는 구현 예시이다. supports 반환 결과 false이면 검증할 수 없다.

public class UserValidator implements Validator {
	@Override
	public boolean supports (Class<?> clazz) {
		return User. class. isAssignablefrom(clazz); // clazz가 User 또는 그 자손인지 확인
	}
    
	@Override
	public void validate (Object target, Errors errors) {
		User user = (User)target;

		String id = user.getId();

//		if(id==null || "'.equals(id.trim())) {
//			errors.rejectValue("id", "required");
//		}
		// 위의 세 줄과 아래 한 줄이 같은 의미임
		ValidationUtils.rejectIfEmpty0rWhitespace(errors, "id", "required");
		ValidationUtils.rejectIfEmpty0rWhitespace(errors, "pwd", "required");
		
		if(id==null || id.lenath() < 5 || id.length() > 12) {
			errors.rejectValue("id", "required");
		}
	}
}

아래는 Error 인터페이스이다.

public interface Errors {
    // ...
    void reject(String errorCode);			// 객체 전체에 대한 에러 지정
    void rejectValue(String field, String errorCode);	// 필드에 대한 에러 지정
    // ...
}

 


1) 수동 검증

그럼 validator를 이용한 수동 검증 예시를 살펴보자.(직접 제작하는)

예전에는 아래와 같이 컨트롤러 메서드에서 검증했다.

@PostMapping("/register/add")
public String save Model model, User user, BindingResult result) {
	String msg = "";

	String id = user.getId();
    
	if(id==null || m.equalsid.trim())) {
		model.addAttribute("msg", "id는 필수 입력항목입니다.");
		return "redirect:/register/add";
	}

	if(id==null || id.length() < 5 || id.length() > 12) {
		model.addAttribute("msg", "1d의 길이는 5글자이상 12글자 미만입니다.");
		return "redirect:/register/add";
	}
}

 

위와 같이 사용하면 코드가 지저분해지므로 검증하는 부분을 별도로 분리해내서 아래와 같이 사용할 수 있다.

UserValidator userValidator = new UserValidator();
// validator로 검증
// BindingResult가 Errors의 자손이라서 result 넣어줌
userValidator.validate(user, result); 

if(result.hasErrors()) { // 에러가 있으면,
	return "registerForm";
}

 

 

 


2) 자동 검증

다음으로 자동 검증이다.

 

우선 컨트롤러 내에서 @InitBinder를 이용해 Validator를 등록해준다. 그리고 검증할 데이터 앞에 @Valid 애노테이션만 붙여주면 된다.

이 방법은 해당하는 컨트롤러 내에서만 사용 가능하다.

@InitBinder
public void toDate(WebDataBinder binder) {
	SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd") ;
	binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));

	binder.setValidator(new UserValidator()); // validator를 WebDataBinder에 등록
    
	List<Validator> validators = binder.getValidators();
	System.out.println("validators="+validators):
}

@PostMapping("/register/add") // 신규 회원 등록.
// user 파라메터 앞에 @Valid 등록.
public String save(Model m, @Valid User user, BindingResult result) {

	if(result.hasErrors()) { // 에러가 있으면,
		return "registerForm";
	}
}

@Valid 를 사용하기 위해선 mvn repository에서 아래 항목을 추가해줘야한다.

 


2. 글로벌 Validator

하나의 Validator로 여러 객체를 검증할 때 글로벌 Validator로 등록해서 사용할 수 있다. 

 

글로벌 Validator로 등록할 땐 servlet-context.xml 파일에 아래와 같이 빈을 등록해주면 된다.

그러면 모든 컨트롤러에서 @Valid 애노테이션으로 검증이 가능하다.

<!-- validator 속성으로 빈 등록 -->
<annotation-driven validator="globalValidator"/>	
<!-- 빈 등록 -->
<beans:bean id="globalValidator" class="com.fastcampus.ch2.GlobalValidator"/>

 

글로벌 Validator와 로컬 Validator를 동시에 적용할 땐아래와 같이 @InitBinder로 등록하고 WebDataBinder에 로컬 Validator를 등록하면 된다.(이 때 set이 아니라 add를 써야함!!!)

@InitBinder
public void toDate(WebDataBinder binder) {
	SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd");
	binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false));

//	binder.setValidator(new UserValidator()); // 
	binder.addValidators(new UserValidator()); // validator를 WebDataBinder에 등록
}

 

 

 


3. MessageSource

MessageSource는 다양한 리소스에서 메시지를 읽기 위한 인터페이스이다. 

public interface MessageSource {
	// code=메세지 코드 | args=넘겨줄 인자값 | defaultMessage=메세지 코드 없을 경우 기본값 | locale=지역
	String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
	String getMessage(String code, Object [] args, Locale locale) throws NoSuchMessageException;
	String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

 

servlet-context.xml 파일에 프로퍼티 파일을 메시지 소스로 하는 ResourceBundleMessageSource를 등록해야한다.

<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	<beans:property name="basenames">
		<beans:list>
			<beans:value>error_message</beans:value> <!-- /src/main/resources/error_message.properties --> 
		</beans:list>
	</beans:property>
	<beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean?

 

그리고 에러 코드에 대한 메세지가 있는 error_message.properties 파일을 추가해줘야한다. (경로는 위에 error_message 옆에 주석처리 된 곳)

- 등호를 구분자로 '메세지 코드=메세지' 와 같이 작성한다.

- {0}, {1} .. 와 같은 부분은 MessageSource의 getMessage 메서드에서 매개변수 args에 들어가는 값을 받아온다. (ex. {"5", "11"} )

required=필수 항목입니다.
required.user.pwd=사용자 비밀번호는 필수 항목입니다.
invalidLenth.id=아이디의 길이는 {1}~{2}사이어야 합니다.

참고로 에러 코드에 requierd 라고만 적었어도 메세지 코드를 찾을 땐 필드명, 객체명 등을 붙여서 찾는다.

따라서 메세지를 찾을 때 찾는 순서는 required.user.id -> required.id -> required.java.lang.String -> required -> defaultMessage 와 같다.

따라서 메세지를 작성할 때 일반적인 값으로 required,  이렇게 주고 조금 더 세부적으로 required.user.id=~~ 작성할 수가 있다.

 

 

 


4. 검증 메세지의 출력

1. 스프링이 제공하는 커스텀 태그 라이브러리를 사용

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

 

2. <form>대신 <form:form> 사용

(action에는 기존 주소, method는 post가 기본으로 붙는 것 같다. 틀리다면 댓글 부탁드립니다.)

<form:form modelAttribute="user"> <!-- modelAttribute에 검증할 객체 넣어줌 -->

<!-- 그러면 아래 코드처럼 바뀜 -->
<form id="user" action="ch2/register/add" method="post">

 

3. 폼 태그 안에서 <form:errors>로 에러를 출력. path에 에러 발생 필드를 지정 (* 지정하면 모든 필드의 에러 출력)

<form:errors path="id" cssClass="msg" />

<!-- 그러면 아래 코드처럼 바뀜 -->
<span id="id.errors" class="msg">필수 입력 항목입니다.</span>

 

 

 


참조

https://fastcampus.co.kr/dev_academy_nks

 

스프링의 정석 : 남궁성과 끝까지 간다 | 패스트캠퍼스

국비지원 조기 마감 신화, 베스트셀러 'JAVA의 정석'의 저자 남궁성의 Spring 강의입니다! 오픈톡방과 카페에서 평생 AS를 제공하며 완강과 취업까지 도와드립니다. 지금 할인가로 확인하세요!

fastcampus.co.kr