JSON Java 8 định dạng LocalDateTime trong Spring Boot


112

Tôi đang gặp sự cố nhỏ với việc định dạng Java 8 LocalDateTime trong Ứng dụng khởi động mùa xuân của mình. Với ngày 'bình thường', tôi không gặp vấn đề gì, nhưng các trường LocalDateTime được chuyển đổi thành như sau:

"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"
    }
  }

Trong khi tôi muốn chuyển đổi nó thành một cái gì đó như:

"startDate": "2015-01-01"

Mã của tôi trông như thế này:

@JsonFormat(pattern="yyyy-MM-dd")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
public LocalDateTime getStartDate() {
    return startDate;
}

Nhưng một trong hai chú thích trên không hoạt động, ngày tháng tiếp tục được định dạng như trên. Đề xuất được chào đón!

Câu trả lời:


134

cập nhật : Spring Boot 2.x không yêu cầu cấu hình này nữa. Tôi đã viết một câu trả lời cập nhật hơn ở đây .


(Đây là cách làm trước Spring Boot 2.x, nó có thể hữu ích cho những người làm việc trên phiên bản Spring Boot cũ hơn)

Cuối cùng tôi đã tìm thấy ở đây cách làm điều đó. Để khắc phục, tôi cần một phụ thuộc khác:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.4.0")

Bằng cách bao gồm sự phụ thuộc này, Spring sẽ tự động đăng ký một bộ chuyển đổi cho nó, như được mô tả ở đây . Sau đó, bạn cần thêm những thứ sau vào application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false

Điều này sẽ đảm bảo rằng một trình chuyển đổi chính xác được sử dụng và ngày tháng sẽ được in ở định dạng 2016-03-16T13:56:39.492

Chú thích chỉ cần thiết trong trường hợp bạn muốn thay đổi định dạng ngày.


24
Có lẽ giá trị bao gồm các chú thích sau - @JsonSerialize(using = LocalDateTimeSerializer.class)...
Nick Grealy

3
Có lẽ tốt hơn là chỉ sử dụng một application.propertiesmục nhập, như câu trả lời @patelb đề xuất.
phát hành

Không làm việc. Nhưng câu trả lời của patelib chỉ hoạt động tốt!
Mykhaylo Kopytonenko

Theo lưu ý, chúng tôi cần @JsonSerializechú thích mà Nick đã đề cập để làm cho nó hoạt động.
pennstatephil

92

Tôi đã thêm phần com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1phụ thuộc và bắt đầu nhận ngày ở định dạng sau:

"birthDate": [
    2016,
    1,
    25,
    21,
    34,
    55
  ]

đó không phải là điều tôi muốn nhưng tôi đã tiến gần hơn. Sau đó tôi đã thêm phần sau

spring.jackson.serialization.write_dates_as_timestamps=false

đến tệp application.properties đã cung cấp cho tôi định dạng chính xác mà tôi cần.

"birthDate": "2016-01-25T21:34:55"

2
Làm việc ra khỏi hộp khi bao gồm jackson-datatype-jsr310phụ thuộc. Đây phải là câu trả lời được chấp nhận.
phát hành

6
Là một FYI, phần application.properties có thể được thực hiện thông qua Java cấu hình nếu bạn đang cấu hình ObjectMapper với:mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
justin

31

Đây là trong maven, với thuộc tính để bạn có thể sống sót giữa các lần nâng cấp khởi động mùa xuân

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
</dependency>

1
Sử dụng giải pháp này với @NickGrealy bình luận: Có lẽ giá trị bao gồm các chú thích sau -@JsonSerialize(using = LocalDateTimeSerializer.class)
HairOfTheDog

19

1) Sự phụ thuộc

 compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.8.8' 

2) Chú thích với định dạng ngày-giờ.

public class RestObject {

    private LocalDateTime timestamp;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    public LocalDateTime getTimestamp() {
        return timestamp;
    }
}

3) Cấu hình mùa xuân.

@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;
    }
}

2
Cám ơn rất nhiều. @JsonFormat là một trong những giải pháp đó cho tôi. Không có giải pháp nào ở trên phù hợp với tôi vì một số lý do
theprogrammer

7

Tôi đã tìm thấy một giải pháp khác mà bạn có thể chuyển đổi nó sang bất kỳ định dạng nào bạn muốn và áp dụng cho tất cả kiểu dữ liệu LocalDateTime và bạn không cần phải chỉ định @JsonFormat phía trên mọi kiểu dữ liệu LocalDateTime. trước tiên hãy thêm phụ thuộc:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

Thêm đậu sau:

@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;
    }
}

trong tệp cấu hình của bạn, hãy thêm phần sau:

@Import(Java8DateTimeConfiguration.class)

Điều này sẽ tuần tự hóa và hủy tuần tự hóa tất cả các thuộc tính LocalDateTime và ZonedDateTime miễn là bạn đang sử dụng objectMapper được tạo bởi spring.

Định dạng mà bạn nhận được cho ZonedDateTime là: "2017-12-27T08: 55: 17.317 + 02: 00 [Asia / Jerusalem]" cho LocalDateTime là: "2017-12-27T09: 05: 30.523"


Probabaly bạn cần thay val bean thành SimpleModule bean = new SimpleModule ();
Abhishek Galoda

Đây có phải là dành cho Java 9 không?
Daniel Dai

@DanielDai Đây là trong Java 8.
Ida Amit

@Abhi, SimpleModulemở rộng Module. Modulelà một trừu tượng. val bean = new SimpleModule(); hoạt động hoàn hảo.
Ida Amit,

đối với SpringBoot phiên bản 1.5.3.RELEASE không cần thiết để thêm phụ thuộc jackson-datatype-jsr310.
Ngày 13

7

Viết câu trả lời này như một lời nhắc nhở cho tôi.

Tôi kết hợp một số câu trả lời ở đây và cuối cùng tôi đã làm việc với một cái gì đó như thế này. (Tôi đang sử dụng SpringBoot 1.5.7 và 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;

}

1
bạn có thể muốn thêm nhập cho DateTimeFormatvà những người khác.
Prayagupd

4

Công việc này ổn:

Thêm phần phụ thuộc:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>

Thêm chú thích:

@JsonFormat(pattern="yyyy-MM-dd")

Bây giờ, bạn phải lấy đúng định dạng.

Để sử dụng trình ánh xạ đối tượng, bạn cần đăng ký JavaTime

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

1

Như đã đề cập, spring-boot sẽ tìm nạp tất cả những gì bạn cần (cho cả web và webflux starter).

Nhưng điều tốt hơn nữa - bạn không cần phải tự mình đăng ký bất kỳ mô-đun nào. Hãy xem ở đây . Vì @SpringBootApplicationsử dụng ẩn @EnableAutoConfiguration, nó có nghĩa là JacksonAutoConfigurationsẽ tự động được thêm vào ngữ cảnh. Bây giờ, nếu bạn nhìn vào bên trong JacksonAutoConfiguration, bạn sẽ thấy:

    private void configureModules(Jackson2ObjectMapperBuilder builder) {
        Collection<Module> moduleBeans = getBeans(this.applicationContext,
                Module.class);
        builder.modulesToInstall(moduleBeans.toArray(new Module[0]));
    }

Cái này sẽ được gọi trong quá trình khởi tạo và sẽ tìm nạp tất cả các mô-đun mà nó có thể tìm thấy trong classpath. (Tôi sử dụng Spring Boot 2.1)


1

Tôi đang sử dụng Springboot 2.0.6 và vì một số lý do, các thay đổi yml của ứng dụng không hoạt động. Và tôi cũng có nhiều yêu cầu hơn.

Tôi đã thử tạo ObjectMapper và đánh dấu nó là Chính nhưng khởi động mùa xuân phàn nàn rằng tôi đã có jacksonObjectMapper được đánh dấu là Chính !!

Vì vậy, đây là những gì tôi đã làm. Tôi đã thực hiện các thay đổi đối với trình liên kết nội bộ.

Serializer và Deserializer của tôi đặc biệt - chúng xử lý 'dd / MM / YYYY'; và trong khi hủy tuần tự hóa - nó cố gắng hết sức để sử dụng 3-4 định dạng phổ biến để đảm bảo tôi có một số 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;
}

0

@JsonDeserialize(using= LocalDateDeserializer.class) không hoạt động đối với tôi với sự phụ thuộc dưới đây.

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version> 2.9.6</version>
</dependency>

Tôi đã sử dụng công cụ chuyển đổi mã dưới đây để giải mã ngày tháng thành một 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();
    }
}

0

chỉ cần sử dụng:

@JsonFormat(pattern="10/04/2019")

hoặc bạn có thể sử dụng mẫu tùy thích, ví dụ: ('-' in place of '/')


Câu trả lời này đã được chia sẻ trước đây, nhưng sau đó với cú pháp chính xác.
Erik Pragt

0

Tôi đang sử dụng Spring Boot 2.1.8. Tôi đã nhập khẩu

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
</dependency>

trong đó bao gồm jackson-datatype-jsr310 .

Sau đó, tôi phải thêm các chú thích này

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("date")
LocalDateTime getDate();

Và nó hoạt động. JSON trông giống như sau:

"date": "2020-03-09 17:55:00"

Gợi ý: spring-boot-starter-jsonchỉ cần bao gồm nếu spring-boot-starter-webthiếu.
judomu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.