[Spring] 데이터의 검증 Validator

Jeini·2023년 5월 25일
0

🍃  Spring

목록 보기
14/33
post-thumbnail

💡 Validator


✔️ 객체를 검증하기 위한 인터페이스. 객체 검증기 구현에 사용

public interface Validator {
	// 이 검증기로 검증가능한 객체인지 알려주는 메서드
	boolean supports(Class<?> clazz);
    // 객체를 검증하는 메서드 - target: 검증할 객체, errors: 검증 시 발생 한 에러저장소
    void vaildate(@Nullable Object target, Errors errors);
}
  • BindingResult 인터페이스는 Errors 의 자손이다.
    : 앞에서 데이터를 변환하고 결과를 BindingResult 에 저장했듯이, Validator 도 검증한 데이터를 Errors 에 저장한다.

✏️ Validator 수동 검증

  • supports() 는 User타입과 그의 자손객체만 들어오게 되어있다.
    : false로 반환될 시, 검증하지 못한다.
    : isAssignable 대신 equals 써도 된다.

  • validate() 는 실제 검증하는 메서드
    : User로 형변환 하기 전에, instanceof로 먼저 확인을 해야 하는데 이미 supports() 에서 걸러주고 있기 때문에 굳이 사용하지 않았다.

  • id가 null이거나 id에 공백이 있으면 id필드에서 required라는 에러 코드를 저장한다.
    : if문 쓰면 너무 길어지니까, ValidationUtils.rejectIfEmptyOfWhitespace() 를 사용한다.

✔️ ValidationUtils.rejectIfEmptyOfWhitespace(errors, iv, 에러코드)
: 해당 iv가 null이거나 공백일 시 errors에 저장

✏️ 바꾸기 전

✏️ 바꾼 후

// 1. 유효성 검사
// 수동 검증 - Validator를 직접 생성하고, validator()를 직접 호출
UserValidator userValidator = new UserValidator();
userValidator.validate(user, result);
		
// User객체를 검증한 결과 에러가 있으면, registerForm을 이용해서 에러를 보여줘야 함.
if(result.hasErrors()) {
	return "registerForm";
}
  • Validator를 배우기 전에는 Controller에다가 직접 검증을 했다.
    : 지저분 해 보이니까, Validator를 활용함으로써 관심사를 분리하였다.
    ➡️ 분리하고 나니까 훨씬 코드가 깔끔해지고 간단해졌다.

  • Validator를 생성하고 메서드를 호출해서 검증한다.
    ➡️ 검증하고 나면 result에 에러가 있는지 확인한다.
    ➡️ 에러가 있으면 registerForm View를 반환

✏️ Validator 자동 검증

  • @InitBinder 를 이용해서 Validator 등록
    : binder.setValidator() 로 등록

  • 검증할 대상에 @Valid 를 붙여주면 된다.

❗️ @Valid 등록

✔️ Spring에 없어서 maven.api에 직접 받아와야 함

✏️ pom.xml에다가 validation api 등록

<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

⚙️ Maven update 해주기

✏️ 결과

  • 아이디와 비밀번호에 111을 넣어준다.
    ➡️ 다시 registerForm으로 되돌아간다.

  • 두개의 BindingResult가 에러난 것을 확인할 수 있다.
    : 111(5 이상의 값을 안넣어서 에러)의 값을 넣었는데 검증에 실패해서 거절됨.

  • required 라고 에러코드를 저장 ➡️ 여러개의 에러코드를 만들어내서 해당하는 메세지를 찾음

  • arguments: 에러메시지를 사용 할 값

  • defalut message는 안적어서 null

📌 @InitBinder 가 붙은 메서드안에다가 setValidator를 써서 로컬 validator로 등록
➡️ 검증 할 객체 앞에 @Valid 달아줌

✏️ 글로벌 Validator

✔️ 모든 Controller에서 검증기가 필요할 때 사용
✔️ 하나의 Validator로 여러 객체를 검증할 때 사용

✏️ Servlet-context.xml에 글로벌 Validator 등록

<annotation-driven validator="globalValidator"/>
<beans:bean id="globalValidator" class="kr.ac.jipark09.GlobalValidator"/>
  • Servlet-context.xml에 자바 빈 등록

  • annotation-driven 태그에 글로벌 Validator 등록

  • 모든 Controller에서 @Valid 로 검증 가능

✏️ 글로벌 Validator와 로컬 Validator를 동시에 적용하는 방법

  • @InitBinder 가 붙은 메서드를 만들고 addvalidators()를 붙여서 로컬 Validator를 만든다.

  • set이 아닌 add 를 써야 한다.
    : 글로벌 Validator에다가 등록하는 방법이기 때문

✏️ 결과

  • 글로벌과 로컬 Validator가 잘 뜬 것을 확인

✏️ 결과: 글로벌 Validator로 검증

💡 Errors 인터페이스


✔️ 유효성 검증 결과를 저장할 때 사용

public interface Errors {
	// 객체 전체에 대한 에러를 저장
	void reject(String errorCode);
    // 어떤 필드의 에러를 저장 (id / pw -> iv를 의미)
    void rejectValue(String field, String errorCode);
    ...
}
  • String 디폴트 메시지를 줄 수도 있다. (거의 잘 안씀)

  • 아이디와 패스워드 둘다 틀렸을 경우 reject() 를 써서 "아이디 또는 패스워드가 틀렸습니다." 라는 문구를 많이 씀

  • rejectValue 가 많이 쓰임

📎 Errors인터페이스와 BindingResult인터페이스

📌 Errors

  • org.sprigFramework.validation.Errors
  • 유효성 검증 결과를 저장할 때 사용

📌 BindingResult

  • org.springFramework.validation.BindingResult
  • Errors의 하위 인터페이스로서 폼 값을 커맨드 객체에 바인딩한 결과를 저장하고 에러코드로 메세지를 가져온다.

📎 Errors 인터페이스가 제공하는 메서드(반환 타입 void)

✏️ reject(String errorCode)

  • 전 객체에 대한 글로벌 에러 코드를 추가

✏️ reject(String errorCode, String defaultMessage)

  • 전 객체에 대한 글로벌 에러코드를 추가하고, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage를 사용

✏️ reject(String errorCode, Object[] errorArgs, String defaultMessage)

  • 전 객체에 대한 글로벌 에러코드를 추가, 메세지 인자로 errorArgs를 전달, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage를 사용

✏️ rejectValue(String field, String errorCode)

  • 필드에 대한 에러코드를 추가

✏️ rejectValue(String field, String errorCode, String defaultMessage)

  • 필드에 대한 에러코드를 추가 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage를 사용

✏️ rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage)

  • 필드에 대한 에러코드를 추가, 메세지 인자로 errorArgs를 전달, 에러코드에 대한 메세지가 존재하지 않을 경우 defaultMessage사용

📎 Errors 인터페이스의 에러 발생 여부를 확인하기 위한 메서드

✏️ boolean hasErrors()

  • 에러가 존재하는 경우 true 리턴

✏️ int getErrorCount()

  • 에러의 갯수를 리턴

✏️ boolean hasGlobalErrors()

  • reject() 메소드를 이용해서 추가된 글로벌 에러가 존재할 경우 true 리턴

✏️ int getGlobalErrorCount()

  • reject() 메소드를 이용해서 추가된 글로벌 에러 갯수를 리턴

✏️ boolean hasFieldErrors()

  • rejectValue() 메소드를 이용해서 추가된 에러가 존재할 경우 true 리턴

✏️ int getFieldErrorCount()

  • rejectValue() 메소드를 이용해서 추가된 에러 갯수를 리턴

✏️ boolean hasFieldErrors(String field)

  • rejectValue() 메소드를 이용해서 추가한 특정핑드의 에러가 존재할 경우 true 리턴

✏️ int getFieldErrorCoutn(String field)

  • rejectValue() 메소드를 이용해서 추가한 특정필드의 에러 갯수 리턴

💡 MessageSource


✔️ 다양한 리소스에서 메시지를 읽기 위한 인터페이스

  • consol에다가 문장이 나오면 사용자가 뭘 잘못했는지 알 수가 없다.
    ➡️ 사용자 화면에다가 에러를 보여줘야 함 ➡️ MessageSource 이용

✔️ 프로퍼티 파일을 메세지 소스로 하는 ResourceBundleMessageSource를 등록

  • Servlet-context.xml 에 자바 빈으로 등록

  • 주석처리 된 것은 메시지 경로(아래 사진)를 의미
    : 확장자는 properties여야 함

✔️ 에러코드가 있는 파일을 만들어야 함

  • required: 메시지 코드

📌 required.user.id ➡️ required.id ➡️ required.java.lang.String ➡️ required

  • Errors 인터페이스의 errorCode는 메시지 코드의 에러코드와 일치하는지 찾는다.

  • User객체의 아이디 필드를 검증하면 required.user.id를 찾는다. 그게 없으면 required.id 찾고 required.java.lang.String을 찾고 마지막으로 required를 찾는다.
    ➡️ 필드이름, 객체이름, 타입까지 조합을해서 메시지 코드에 일치하는 지 찾는다.

  • required는 일반적이여서 메세지 프로퍼티에 첫 번째로 등록해 놓는다.

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

  • jsp에다 보여줄려면 태그 라이브러리를 붙여야 함

✔️ <form> 대신 <form:form> 사용

<form:form modelAttribute="user>

  • 이렇게 바뀌게 된다.

✔️ <form:erros>로 에러를 출력. path에 에러 발생 필드를 지정(*은 모든 필드의 에러)

<form:errors path="id" cssClass="msg">
  • path: 필드 이름

  • 스팬 태그로 바뀜

✏️ 에러메시지 프로퍼티를 만들고 화면에 발생하는 에러에 대한 메세지를 보여주는 예제

  • /src/main/resources/ 에다가 에러메시지 properties 만들기

  • incoding: UTF-8 설정

<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>
  • Servlet-context.xml 에 등록


Reference
: https://fastcampus.co.kr/dev_academy_nks

profile
Fill in my own colorful colors🎨

0개의 댓글