Validation, Data Binding

박근수·2024년 2월 24일
0

Spring

목록 보기
5/11
post-custom-banner

Validation (유효성 검증)

주로 사용자 또는 타 서버의 요청(http request) 내용에서 잘못된 내용이 있는 지 확인하는 행위

Validation 종류

데이터 검증

  • 필수 데이터의 존재 유무
  • 문자열의 길이나 숫자형 데이터의 경우 값의 범위
  • email, 신용카드 번호 등 특정 형식에 맞춘 데이터

비즈니스 검증

  • 서비스에 정책에 따라 데이터를 확인하여 검증
  • ex) 배달앱인 경우 배달 요청을 할 때 해당 주문 건이 결제 완료 상태인 지 확인
  • 경우에 따라 외부 API를 호출하거나 DB의 데이터까지 조회하여 검증하는 경우도 존재

Spring의 Validation

스프링은 웹 레이어에 종속적이지 않은 방법으로 Validation을 하려고 의도하고 있으며 주로 아래 두 가지 방법을 활용하여 진행 (둘 다 데이터 검증에 가까움)

Java Bean Validation

JavaBean 기반으로 간편하게 개별 데이터를 검증
요즘에 가장 많이 활용되는 방법 중 하나이며, 아래 코듳럼 JavaBean 내에 어노테이션으로 검증방법을 명시함

public class memberCreationRequest{
	@NotBlank(message="이름을 입력해주세요.")
    @Size(max=64, message="이름의 최대 길이는 64자 입니다.")
    private String name;
    
    @Min(0, "나이는 0보다 커야 합니다.")
    private int age;
    
    @Email("이메일 형식이 잘못되었습니다.")
    private int email;
    
    // the usual getters and setters...
}

요청 dto에 어노테이션으로 명시한 후 아래처럼 @Valid 어노테이션을 해당 @RequestBody에 달게 되면, Java Bean Validation을 수행한 후 문제가 없을 때만 메서드 내부로 진입

  • 검증에 실패가 발생 : MethodArgumentNotValidException 발생
@PostMapping(value = "/member)
public MemberCreationResponse createMember(
	@valid @RequestBody final MemberCrationRequest memberCreationReqeust) {
    	//member creation logics here...
    }

Spring validator 인터페이스 구현을 통한 validation

public class Person{
	private String name;
    private int age;
}

Person이라는 javaBean 객체가 있을 때, 아래는 해당 인스턴스에서만 활용되는 validator이다.
인터페이스에 있는 두 개의 메서드는 아래와 같은 역할을 함

  • supports : 이 validator가 동작할 조건을 정의, 주로 class의 타입을 비교
  • validate : 원하는 검증을 진행
public class PersonValidator implements Validator{
	public boolean supports(Calss clazz){
    	return Person.class.equals(clazz);
    }
    
    public void validate(Object obj, Errors e){
    	ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
        Person p = (Person) obj;
        if (p.getAge() < 0) {
        	e.rejectValue("age", "negativevalue");
        }else if (p.getAge() > 110){
        	e.rejectValue("age", "too.darn.old");
        }
    }
}

Validation 수행 시 주의사항 및 패턴

주의사항

  • validation이 너무 여러곳에 흩어져있으면 테스트 및 유지보수성이 떨어짐
    • 중복된 검증 : 정책 변경 시에는 모든 중복 코드를 수정해야 함
    • 다른 검증 : 여러 곳에서 다른 정책을 따르는 검증이 수행도리 수 있음
  • 가능한 validation은 로직 초기에 수행 후 실패 시에는 exception을 던지는 편이 처리가 편리함

실무 활용 패턴

  • 요청 dto에서 java Bean Validation 으로 단순 데이터(유무, 범위, 형식 등)를 1차 검증
  • 로직 초기에 2차로 비즈니스 검증 수행 후 실패 시에는 Custom Exception(ErrorCode, ErrorMessage를 입력)해서 예외를 던지도록 하고 예외처리하여 응답 생성
  • Spring validator 장단점
    • 장점 : java Bean Validation에 비해 조금 더 복잡한 검증이 가능
    • 단점
      • Valition을 수행하는 코드를 찾기가 어려움
      • 완전히 데이터만 검증하는 것이 아니기 때문에 일부 비즈니스적인 검증이 들어가는 경우가 있음

Data Binding

사용자나 외부 서버의 요청 데이터를 특정 도메인 객체에 저장해서 우리 프로그램에 Request에 담아주는 것을 뜻함

Converter<S, T> Interface

S(Source) 라는 타입을 받아서 T(Target)이라는 타입으로 변환해주는 Interface

public interface Converter(S, T> {
	T convert(S source);
}

Formatter

특정 객체 <-> String 간의 변환을 담당

  • print : API 요청에 대한 응답을 줄 때, Date형식으로 된 데이터를 특정 locale에 맞춘 String으로 변환
  • parse : API 요청을 받아올 때, String으로 된 "2021-01-01 13:15:15:00" 같은 날짜 형식의 데이터를 Date로 변환하도록 함
public final class DateFommatter implements Formatter<Date> {
	public String print(Date date, Locale locale) {
    	return getDateFormat(locale).format(date); 
    }
    
    public Date parse(String formatted, Locale locale) throws ParseException {
    	return getDateFormat(locale).parse(formatted);
    }
    //getDateFormat 등 일부 구현은 핵심에 집중하기 위해 생략
}

Formmater도 Convert와 마찬가지로 Spring Bean으로 등록하면 자동으로 ConversionService에 등록시켜 주기 때문에 필요에 따라 자동으로 동작

profile
개발블로그
post-custom-banner

0개의 댓글