1. Formatter
- 클라이언트 환경에서 문자열 ↔️ 객체 간 변환을 처리하는 인터페이스
특징
특징 | 설명 |
강타입 기반 | Formatter<T> 제네릭 타입으로 타입 안정성 보장 |
Locale 지원 |
Locale 정보를 기반으로 사용자 친화적인 지역화 포맷 처리 가능
|
양방향 변환 지원 | print(): 객체 → 문자열 parse(): 문자열 → 객체 |
예외 처리 |
변환 실패 시 ParseException 또는 IllegalArgumentException 발생 가능
|
Thread-unsafe |
상태(state)를 가지는 경우 다중 스레드 환경에서 안전하지 않음 (주의 필요)
|
예시) DateFormatter
더보기
public final class DateFormatter implements Formatter<Date> {
private String pattern;
public String print(Date date, Locale locale) { ... }
public Date parse(String formatted, Locale locale) throws ParseException { ... }
}
public class MyDateFormatter implements Formatter<LocalDate> {
@Override
public LocalDate parse(String text, Locale locale) throws ParseException {
if (locale.equals(Locale.KOREA)) {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy.MM.dd"));
} else {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("MM/dd/yyyy"));
}
}
@Override
public String print(LocalDate object, Locale locale) {
if (locale.equals(Locale.KOREA)) {
return object.format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
} else {
return object.format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));
}
}
}
AnnotationFormatterFactory
- 특정 어노테이션이 붙은 필드에 Formatter 적용
예시) @NumberFormat 연결
더보기
public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
public Set<Class<?>> getFieldTypes() { ... }
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) { ... }
public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) { ... }
}
public class MyModel {
@NumberFormat(style = Style.CURRENCY)
private BigDecimal decimal;
@DateTimeFormat(iso = ISO.DATE)
private Date date;
}
Annotation
어노테이션 | 대상 타입 | 기능 설명 |
지원 포맷
|
@DateTimeFormat | Date, Calendar, LocalDate, LocalDateTime | 날짜 및 시간 문자열 ↔ 날짜 객체 | iso, pattern |
@NumberFormat | Number, BigDecimal, Integer 등 | 숫자 ↔ 문자열 | style, pattern |
예시) @DateTimeFormat
더보기
@GetMapping("/date")
public String getDate(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
return "입력 받은 날짜: " + date;
}
@GetMapping("/custom-date")
public String getCustomDate(@RequestParam @DateTimeFormat(pattern = "yyyy/MM/dd") LocalDate date) {
return "입력 받은 날짜: " + date;
}
예시) @NumberFormat
더보기
public class Product {
@NumberFormat(pattern = "#,###.##")
private BigDecimal price;
// getter/setter 생략
}
@PostMapping("/product")
public String addProduct(@ModelAttribute Product product) {
return "가격: " + product.getPrice();
}
- 요청 예시: price=1,234.56
- 자동 변환: "1,234.56" → BigDecimal.valueOf(1234.56)
3. FormatterRegistry
- Formatter, Convereter, Printer, Parser, AnnotationFormatterFactory를 등록하기 위한 SPI
public interface FormatterRegistry extends ConverterRegistry {
void addFormatter(Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}
특징
특징 | 설명 |
중앙 집중식 등록 |
한 곳에서 포맷터를 등록하여 애플리케이션 전반에 걸쳐 일관된 포맷 유지 가능
|
타입 기반 또는 애노테이션 기반 등록 지원 |
특정 타입 또는 특정 애노테이션에 따라 포맷터 등록 가능
(addFormatter, addFormatterForFieldAnnotation) |
ConversionService와 연동 가능 |
FormattingConversionService로 통합되어 Converter, Formatter를 함께 사용 가능
|
4. FormatterRegistrar
- FormatterRegistry에 관련된 포맷터들을 묶어서 등록하기 위한 인터페이스
public interface FormatterRegistrar {
void registerFormatters(FormatterRegistry registry);
}
용도
용도 항목 | 설명 |
카테고리별 포맷터 일괄 등록 |
날짜, 숫자 등 특정 도메인의 관련 포맷터들을 한 번에 등록할 수 있음
|
선언적 등록의 한계 보완 |
애노테이션 기반 또는 개별 등록으로는 처리하기 어려운 경우, 프로그래밍 방식으로 유연하게 등록 가능
|
<T> 타입 ≠ 필드 타입인 경우 |
포맷터의 제네릭 타입 <T>과 실제 적용할 필드 타입이 다를 경우, 명시적으로 매핑하여 등록 가능
|
5. Global Date/Time Format 설정
- 기본적으로 DateFormat.SHORT 스타일로 문자열을 날짜 타입으로 변환. (예: 24. 4. 6. → Date)
- 기본 셋팅 바꾸려면 설정 필요
기본 셋팅 바꾸는 법
@Configuration
public class ApplicationConfiguration {
@Bean
public FormattingConversionService conversionService() {
// 1. 기본 포맷터 등록 X
DefaultFormattingConversionService conversionService =
new DefaultFormattingConversionService(false);
// 2. @NumberFormat 사용 가능하도록 수동 등록
conversionService.addFormatterForFieldAnnotation(
new NumberFormatAnnotationFormatterFactory());
// 3. LocalDate, LocalDateTime 등에 yyyyMMdd 포맷 적용
DateTimeFormatterRegistrar dateTimeRegistrar = new DateTimeFormatterRegistrar();
dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
dateTimeRegistrar.registerFormatters(conversionService);
// 4. java.util.Date 등에 yyyyMMdd 포맷 적용
DateFormatterRegistrar dateRegistrar = new DateFormatterRegistrar();
dateRegistrar.setFormatter(new DateFormatter("yyyyMMdd"));
dateRegistrar.registerFormatters(conversionService);
return conversionService;
}
}
- 기본 포맷터 등록 하지 말기
- @NumbeFormat 수동으로 다시 등록
- java.time용 전역 날짜 포맷 등록 (LocalDate, LocalDateTime)
- java.util용 전역 날짜 포맷 등록 (Date, Calendar)
출처
'Spring > Spring' 카테고리의 다른 글
[Spring][Validation] 1. Validator Interface (0) | 2025.04.06 |
---|---|
[Spring][Object] 1. Data Binding (0) | 2025.04.06 |
[Spring][Field] 1. Type Conversion (0) | 2025.04.06 |
[Spring][Core] 3-5. Container: Additional Capabilities of the ApplicationContext (0) | 2025.04.06 |
[Spring][Core] 3-4. Container: Environment Abstraction (0) | 2025.04.06 |