JSON Java 8 LocalDateTime формат в Spring Boot
У меня небольшая проблема с форматированием Java 8 LocalDateTime в моем приложении Spring Boot. С "нормальными" датами у меня нет проблем, но поля LocalDateTime преобразуются в следующие:
"startDate" : {
"year" : 2010,
"month" : "JANUARY",
"dayOfMonth" : 1,
"dayOfWeek" : "FRIDAY",
"dayOfYear" : 1,
"monthValue" : 1,
"hour" : 2,
"minute" : 2,
"second" : 0,
"nano" : 0,
"chronology" : {
"id" : "ISO",
"calendarType" : "iso8601"
}
}
Хотя я хотел бы преобразовать его в нечто вроде:
"startDate": "2015-01-01"
Мой код выглядит так:
@JsonFormat(pattern="yyyy-MM-dd")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
public LocalDateTime getStartDate() {
return startDate;
}
Но ни одна из приведенных выше аннотаций не работает, дата продолжает форматироваться, как указано выше. Предложения приветствуются!
17 ответов
Я наконец нашел здесь, как это сделать. Чтобы это исправить, мне нужна была другая зависимость:
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")
Включив эту зависимость, Spring автоматически зарегистрирует конвертер для нее, как описано здесь. После этого вам нужно добавить следующее в application.properties:
spring.jackson.serialization.write_dates_as_timestamps=false
Это обеспечит использование правильного конвертера, а даты будут напечатаны в формате 2016-03-16T13:56:39.492
Аннотации нужны только в том случае, если вы хотите изменить формат даты.
Я добавил com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1 и начал получать дату в следующем формате:
"birthDate": [
2016,
1,
25,
21,
34,
55
]
это не то, что я хотел, но я становился ближе. Затем я добавил следующее
spring.jackson.serialization.write_dates_as_timestamps=false
в файл application.properties, который дал мне правильный формат, который мне был нужен.
"birthDate": "2016-01-25T21:34:55"
Вот он в Maven, со свойством, чтобы вы могли выжить между весенними обновлениями загрузки
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
1) Зависимость
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.8.8'
2) Аннотация с форматом даты и времени.
public class RestObject {
private LocalDateTime timestamp;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime getTimestamp() {
return timestamp;
}
}
3) Spring Config.
@Configuration
public class JacksonConfig {
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
System.out.println("Config is starting.");
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
}
Пишу этот ответ как напоминание и для меня.
Я объединил несколько ответов здесь, и в итоге мой работал с чем-то вроде этого. (Я использую SpringBoot 1.5.7 и Lombok 1.16.16)
@Data
public Class someClass {
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime someDate;
}
Я нашел другое решение, которое вы можете преобразовать в любой формат и применить ко всем типам данных LocalDateTime, и вам не нужно указывать @JsonFormat над каждым типом данных LocalDateTime. Сначала добавьте зависимость:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
Добавьте следующий боб:
@Configuration
public class Java8DateTimeConfiguration {
/**
* Customizing
* http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html
*
* Defining a @Bean of type Jackson2ObjectMapperBuilder will allow you to customize both default ObjectMapper and XmlMapper (used in MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter respectively).
*/
@Bean
public Module jsonMapperJava8DateTimeModule() {
val bean = new SimpleModule();
bean.addDeserializer (ZonedDateTime.class, new JsonDeserializer<ZonedDateTime>() {
@Override
public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return ZonedDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
}
});
bean.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return LocalDateTime.parse(jsonParser.getValueAsString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
});
bean.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
@Override
public void serialize(
ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zonedDateTime));
}
});
bean.addSerializer(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
@Override
public void serialize(
LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(localDateTime));
}
});
return bean;
}
}
в вашем конфигурационном файле добавьте следующее:
@Import(Java8DateTimeConfiguration.class)
Это будет сериализовать и десериализовать все свойства LocalDateTime и ZonedDateTime, если вы используете objectMapper, созданный Spring.
Формат, который вы получили для ZonedDateTime: "2017-12-27T08:55:17.317+02:00[Азия / Иерусалим]" для LocalDateTime: "2017-12-27T09:05:30.523"
Это сработало для меня.
Я определил поле BirthDate в моем DTO, как указано ниже:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthDate;
И в теле запроса я передал дату рождения в следующем формате:
{
"birthDate": "2021-06-03 00:00:00"
}
Я использую Spring Boot 2.1.8. Я импортировал
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
который включает файл jackson-datatype-jsr310.
Затем мне пришлось добавить эти аннотации
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("date")
LocalDateTime getDate();
и это работает. JSON выглядит так:
"date": "2020-03-09 17:55:00"
Это прекрасно работает:
Добавьте зависимость:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
Добавьте аннотацию:
@JsonFormat(pattern="yyyy-MM-dd")
Теперь вы должны получить правильный формат.
Чтобы использовать объект маппер, вам нужно зарегистрировать JavaTime
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
Как уже упоминалось, Spring-Boot будет загружать все, что вам нужно (как для веб-, так и для начала webflux).
Но что еще лучше - вам не нужно регистрировать какие-либо модули самостоятельно. Посмотрите здесь. поскольку @SpringBootApplication
использования @EnableAutoConfiguration
под капотом это значит JacksonAutoConfiguration
будет добавлен в контекст автоматически. Теперь, если вы посмотрите внутрь JacksonAutoConfiguration
, ты увидишь:
private void configureModules(Jackson2ObjectMapperBuilder builder) {
Collection<Module> moduleBeans = getBeans(this.applicationContext,
Module.class);
builder.modulesToInstall(moduleBeans.toArray(new Module[0]));
}
Этот парень будет вызываться в процессе инициализации и будет извлекать все модули, которые он может найти в пути к классам. (Я использую Spring Boot 2.1)
Это сработало для меня.
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
public Class someClass {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime sinceDate;
}
Следующие аннотации работают для меня
@JsonSerialize(using = LocalDateSerializer.class) and
@JsonFormat(pattern="yyyy-MM-dd")
Я использую Springboot 2.0.6 и по какой-то причине изменения в приложении yml не работают. А также у меня было больше требований.
Я попытался создать ObjectMapper и пометить его как Primary, но весенняя загрузка жаловалась, что у меня уже есть jacksonObjectMapper как помеченный как Primary!!
Так вот что я сделал. Я внес изменения во внутренний картограф.
Мой Serializer и Deserializer особенные - они имеют дело с 'dd/MM/YYYY'; и при десериализации - он старается использовать 3-4 популярных формата, чтобы убедиться, что у меня есть LocalDate.
@Autowired
ObjectMapper mapper;
@PostConstruct
public ObjectMapper configureMapper() {
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, true);
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
SimpleModule module = new SimpleModule();
module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
module.addSerializer(LocalDate.class, new LocalDateSerializer());
mapper.registerModule(module);
return mapper;
}
Добавлен
group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.8.8'
в блок компиляции gradle
и в
application.yml
файл
spring:
jackson:
serialization:
write_dates_as_timestamps: false
если вы используете
application.properties
файл добавить следующее
spring.jackson.serialization.write_dates_as_timestamps=false
если вы хотите применить собственный формат, вы можете применить аннотацию
@JsonFormat(pattern = "yyyy-MMMM-dd hh:mm:ss")
private LocalDateTime date;
У меня все стало нормально работать
Если вы хотите настроить его глобально, не используя свойства, определенные в файле application.properties , как отмечено в других ответах, вы можете предоставить свой собственный картограф Джексона и настроить для него формат даты следующим образом:
@Configuration
public class SpringConfig {
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder()
.dateFormat(new StdDateFormat());
}
}
@JsonDeserialize(using= LocalDateDeserializer.class)
у меня не работает с приведенной ниже зависимостью.
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version> 2.9.6</version>
</dependency>
Я использовал приведенный ниже конвертер кода для десериализации даты в java.sql.Date
,
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@SuppressWarnings("UnusedDeclaration")
@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<java.time.LocalDate, java.sql.Date> {
@Override
public java.sql.Date convertToDatabaseColumn(java.time.LocalDate attribute) {
return attribute == null ? null : java.sql.Date.valueOf(attribute);
}
@Override
public java.time.LocalDate convertToEntityAttribute(java.sql.Date dbData) {
return dbData == null ? null : dbData.toLocalDate();
}
}
Просто используйте:
@JsonFormat(pattern="10/04/2019")
или вы можете использовать шаблон, как вам нравится, например: ('-' in place of '/')