@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InsertExcelVO {
private String modelName;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date openingDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date deliveryDate;
위 코드는 원본의 코드를 각색한 코드이다.
나는 현재 Excel의 행들을 DB 스키마에 맞춰서 매핑시켜 넣어주는 기능을 구현 중에 있다.
이 때 나는 엑셀에 있는 날짜 데이터들을 DB Date 타입에 맞춰서 넣어주려고 하는데, 이 때 중간에서 타입을 변환 시켜주기 위해서 @DateTimeFormat
이라는 어노테이션을 사용하였다.
@DateTimeFormat
이 어떤 역할을 하길래 나는 사용했을까?
/**
* Declares that a field should be formatted as a date time.
*
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
* The first character of the code is the date style, and the second character is the time style.
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
* A date or time may be omitted by specifying the style character '-'.
*
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs).
* When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
* When the iso attribute is specified, if takes precedence over the style attribute.
* When no annotation attributes are specified, the default format applied is style-based
* with a style code of 'SS' (short date, short time).
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
* @see org.joda.time.format.DateTimeFormat
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DateTimeFormat {
/**
* The style pattern to use to format the field.
* <p>Defaults to 'SS' for short date time. Set this attribute when you wish to format
* your field in accordance with a common style other than the default style.
*/
String style() default "SS";
/**
* The ISO pattern to use to format the field.
* The possible ISO patterns are defined in the {@link ISO} enum.
* <p>Defaults to {@link ISO#NONE}, indicating this attribute should be ignored.
* Set this attribute when you wish to format your field in accordance with an ISO format.
*/
ISO iso() default ISO.NONE;
/**
* The custom pattern to use to format the field.
* <p>Defaults to empty String, indicating no custom pattern String has been specified.
* Set this attribute when you wish to format your field in accordance with a custom
* date time pattern not represented by a style or ISO format.
*/
String pattern() default "";
/**
* Common ISO date time format patterns.
*/
public enum ISO {
/**
* The most common ISO Date Format {@code yyyy-MM-dd},
* e.g. 2000-10-31.
*/
DATE,
/**
* The most common ISO Time Format {@code HH:mm:ss.SSSZ},
* e.g. 01:30:00.000-05:00.
*/
TIME,
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. 2000-10-31 01:30:00.000-05:00.
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
/**
* Indicates that no ISO-based format pattern should be applied.
*/
NONE
}
}
위 코드는 @DateTimeFormat
어노테이션의 코드이다.
위 설명을 조금 간략화 시켜보면 다음과 같다.
위 설명이 무슨 말인지 더 쉽게 풀어가보면 아래와 같다.
@DateTimeFormat
어노테이션은 스프링 프레임워크에서 날짜와 시간을 나타내는 문자열을 자바의 java.util.Date
, java.util.Calendar
, java.time.LocalDate
, java.time.LocalTime
, java.time.LocalDateTime
등과 같은 날짜 및 시간 객체로 변환할 때 사용된다.
내부적으로 @DateTimeFormat
어노테이션은 문자열을 해당 날짜 또는 시간 객체로 변환하는 데 사용되는 포맷을 지정한다.
즉, 이 어노테이션을 사용하여 속성에 적용된 문자열을 해당하는 자바 날짜 또는 시간 객체로 변환할 때 사용할 포맷을 지정할 수 있다.
예를 들어, 다음과 같이 @DateTimeFormat
어노테이션을 사용하여 문자열을 날짜 객체로 변환하는 방법을 지정할 수 있다.
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
위 예제에서는 startDate
필드의 값이 "yyyy-MM-dd"
형식의 문자열로 제공되어야 하며, 이 문자열은 java.util.Date
객체로 자동 변환된다.
그러나 @DateTimeFormat
을 사용할 때 중요한 점이 있다.
@DateTimeFormat
은 @RequestBody나 @ResponseBody에서는 동작하지 않는다.
그 이유는 @RequestBody나 @ResponseBody 어노테이션은 Jackson 라이브러리가 사용된다.
Jackson 라이브러리는 Java에서 제공하는 JSON 파싱 라이브러리이다.
여기서 눈치가 빠른 사람들은 알았겠지만, 위 @DateTimeFormat은 Spring 어노테이션이다.
Spring에서 Jackson을 의존하기에 Spring은 Jackson을 알고 있지만, Jackson은 Spring을 알지 못한다.
그렇기에 Jackson 라이브러리가 사용되는 @RequestBody나 @ResponseBody를 이용한 역/직렬화에서는 작동하지 않는 것이다.
그러나 내 코드에서 @DateTimeFormat
이 잘 작동했던 이유는 @ModelAttribute
나 @RequestParam
에서는 Jackson 라이브러리가 동작하지 않기 때문이다.
그렇다면 @RequestBody나 @ResponseBody에서는 어떻게 날짜를 역/직렬화 하면 좋을까??
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InsertExcelVO {
private String modelName;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MMM-yyyy", timezone = "Asia/Seoul")
private Date openingDate;
추가적으로 Spring에서는 기본으로 사용하는 날짜 패턴(yyyy-MM-ddTHH:mm:ss)의 경우 별도의 어노테이션을 달지 않아도 자동으로 바인딩(==역직렬화)된다.
꿀팁 감사합니다 : ]