Formatter로 “문자열 → 타입” 변환 규칙을 등록한다
스프링 MVC의 파라미터 바인딩은 편하다.
- 요청 파라미터가 문자열로 들어와도
- int/boolean 같은 기본 타입은 자동 변환해주고
- DTO 필드에도 알아서 채워준다
그런데 실전에서 가장 자주 터지는 타입이 있다.
- 날짜(LocalDate, LocalDateTime)
1) 왜 날짜에서 에러가 자주 나나
HTTP 요청 파라미터는 기본적으로 전부 문자열이다.
예를 들어 사용자가 폼에서 날짜를 입력하면 이런 문자열이 온다.
- dueDate=2020-10-10
문제는 스프링이 이 문자열을
- LocalDate 객체로 바꾸는 규칙을 “항상 자동으로 알 수는 없다”는 점이다.
즉 바인딩 과정에서
- “String을 LocalDate로 변환할 수 없다”
- 같은 타입 변환 에러가 발생할 수 있다.
// ================================
// [문제 상황] 스프링 MVC가 "문자열"을 LocalDate로 자동 변환 못 해서 에러가 나는 케이스
// - 요청: dueDate=2020-10-10
// - DTO: LocalDate dueDate
// ================================
@Data
public class TodoDTO {
private String title;
private LocalDate dueDate; // ✅ 여기서 바인딩 문제가 자주 난다
}
2) 해결 방법 1: @DateTimeFormat
DTO 필드에 날짜 형식을 명시하면 된다.
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate dueDate;
이렇게 하면 스프링이
- yyyy-MM-dd 패턴으로 문자열을 파싱해서 LocalDate로 변환한다.
즉 특정 필드/파라미터에 대해 “형식”을 선언하는 방식이다.
3) 해결 방법 2: Formatter 등록 (전역 규칙을 만드는 방식)
`@DateTimeFormat`은 간단하지만
프로젝트 전체에서 동일한 규칙을 강제하거나, 커스텀 규칙이 더 필요하면 Formatter를 쓴다.
Formatter는 한 문장으로 말하면 이거다.
문자열 ↔ 특정 타입 변환 규칙을 코드로 등록하는 장치
Formatter는 두 메서드를 가진다.
- parse(String text, Locale locale) : 문자열 → 타입
- print(T object, Locale locale) : 타입 → 문자열
LocalDateFormatter는 이런 식이다.
- 2020-10-10 → LocalDate.of(2020,10,10)
4) Formatter는 어디에 등록하나
스프링 MVC에서는 보통 `WebMvcConfigurer`에서 등록한다.
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new LocalDateFormatter());
}
이렇게 등록하면
- 프로젝트 전체에서 LocalDate 바인딩에 이 규칙이 적용될 수 있다.
즉 “전역 타입 변환 규칙”을 등록하는 방식이다.
5) 언제 무엇을 쓰는가
- 빠르게 해결: @DateTimeFormat
- 프로젝트 전체 규칙/커스텀 변환 필요: Formatter 등록
둘 다 결국 같은 문제를 해결한다.
- “문자열로 들어온 요청 데이터를, 원하는 타입으로 변환하는 규칙”을 제공한다
핵심 정리
- HTTP 요청 파라미터는 기본적으로 문자열이다
- LocalDate 같은 타입은 문자열 → 타입 변환 규칙이 필요해서 바인딩 에러가 자주 난다
- @DateTimeFormat은 필드 단위로 형식을 지정하는 쉬운 해결책이다
- Formatter는 문자열 ↔ 타입 변환 규칙을 전역으로 등록하는 방식이다
- Formatter는 WebMvcConfigurer의 addFormatters로 등록한다
'Web > Web Basics' 카테고리의 다른 글
| [스프링과 스프링 MVC] 3. 파라미터 바인딩과 Model (0) | 2026.03.30 |
|---|---|
| [스프링과 스프링 MVC] 2. 스프링 MVC는 “프론트 컨트롤러”로 움직인다 (0) | 2026.03.30 |
| [스프링과 스프링 MVC] 1. DI와 빈(Bean) (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 5. MyBatis 설정 흐름 (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 4. MyBatis는 무엇을 해결하는가 (0) | 2026.03.30 |