학문적으로 여러 세부적인 단계들이 있기도 하지만 실제로 개발자가 주로 챙겨야 하는 검증은 크게 두 종류로 나뉜다.
스프링은 웹 레이어에 종속적이지 않은 방법으로 Validation을 하려고 의도하고 있으며 주로 아래 두가지 방법을 활용하여 Validation을 진행
Java Bean 기반으로 간편하게 개별 데이터를 검증
요즘에 가장 많이 활용되는 방법 중 하나이며, 아래 코드처럼 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을 수행한 후 문제가 없을 때만 메서드 내부로 진입이 된다.
@PostMapping(value = "/member")
public MemeberCreationResponse createMember(
@Valid @RequestBody final MemeberCreationRequest memeberCreationRequest) {
// member creation logics here...
}
public class Person {
private String name;
private int age;
// the usual getters and setters...
}
위처럼 Person이라는 JavaBean 객체가 있을 때, 아래는 해당 인스턴스에서만 활용되는 Validation이다.
인터페이스에 있는 두개의 메서드는 아래와 같은 역할을 한다.
public class PersonValidator implements Validator {
/**
* This Validator validates only Person instances
*/
public boolean supports(Class 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");
}
}
}
사용자나 외부 서버의 요청 데이터를 특정 도메인 객체에 저장해서 우리 프로그램에 Request에 담아주는 것을 뜻한다.
S (Source)라는 타입을 받아서 T (Target)이라는 타입으로 변환해주는 Interface, 인터페이스의 모양은 아래와 같다
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
// 요청
GET /user-info
x-auth-user : {"id":123, "name":"Paul"}
// 유저 객체
public class XAuthUser {
private int id;
private String name;
// the usual getters and setters...
}
@GetMapping("/user-info")
public UserInfoResponse getUserInfo(
@RequestHeader("x-auth-user") XAuthUser xAuthUser){
// get User Info logic here...
}
위 처럼 헤더에 담긴 json 형식 문자열을 XAuthUser에 바로 담고 싶은 경우 아래와 같이 Converter를 Bean으로 등록하면 된다.
@Component
public class XAuthUserConverter implements Converter<String, XAuthUser> {
@Override
public XAuthUser convert(String source) {
return objectMapper.readValue(source, XAuthUser.class);
}
}
이와 비슷하게 PathParameter나 기타 특수한 경우의 데이터를 특정 객체에 담고 싶은 경우
특정 객체 ↔ String간의 변환을 담당
아래 샘플 코드는 Date ↔ String 간의 변환을 수행하는 Formatter이다.
package org.springframework.format.datetime;
public final class DateFormatter 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 등 일부 구현은 핵심에 집중하기 위해 생략...
}
Formatter도 Converter와 마찬가지로 Spring Bean으로 등록하면 자동으로 ConversionService에 등록시켜주기 때문에 필요(요청/응답 시 해당 데이터 타입이 있는 경우)에 따라 자동으로 동작하게 된다.