Tanggal dan waktu kustomisasi musim semi

Bayangkan situasi yang cukup umum: aplikasi Anda berinteraksi dengan klien yang berada di zona waktu berbeda. Anda sering kali harus bekerja dengan tanggal, dan agar sistem berfungsi dengan benar, tanggal tersebut dikirim dengan zona waktu pengirim. Dalam melakukannya, Anda membutuhkan:





  1. Saat permintaan diterima, bawa tanggal ke waktu server dan kerjakan dengannya, dan simpan juga ke database dalam formulir ini





  2. Sebagai tanggapan, kembalikan tanggal dan waktu yang menunjukkan zona waktu server





Untuk mencapai hal ini, Spring menyediakan mekanisme yang mudah untuk menulis serialisasi dan deserialisasi kustom. Keuntungan utamanya adalah kemampuan untuk memindahkan konversi tanggal (dan tipe data lainnya) ke dalam kelas konfigurasi terpisah dan tidak memanggil metode konversi setiap kali dalam kode sumber.





Deserialisasi

Agar Spring memahami bahwa kelas kami yang perlu digunakan untuk (de) serialisasi, itu harus ditandai dengan anotasi @JsonComponent







Nah, untuk menjaga kode sesingkat mungkin, saya akan menggunakan kelas statis internal, yang harus diwarisi dari JsonDeserializer



dan diparameterisasi dengan tipe data yang kita butuhkan. Karena ini JsonDeserializer



 adalah kelas abstrak, kita perlu mengganti metode abstraknyadeserialize()







@JsonComponent
public class CustomDateSerializer {  
  
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    
        @Override
        public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
            return null;
        }
    }
}
      
      



Dari parameter metode, kita mendapatkan string yang diteruskan oleh klien, memeriksanya untuk null dan mendapatkan objek kelas darinya ZonedDateTime







public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
    String date = jsonParser.getText();
    if (date.isEmpty() || isNull(date) {
        return null;
    }
    ZonedDateTime userDateTime = ZonedDateTime.parse(date);
}
      
      



, userDateTime



withZoneSameInstant()



. LocalDateTime







, , , . , .





public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        String date = jsonParser.getText();
        if (date.isEmpty()) {
            return null;
        }
        try {
            ZonedDateTime userDateTime = ZonedDateTime.parse(date);
            ZonedDateTime serverTime = userDateTime.withZoneSameInstant(ZoneId.systemDefault());
            return serverTime.toLocalDateTime();
        } catch (DateTimeParseException e) {
            try {
                return LocalDateTime.parse(date);
            } catch (DateTimeParseException ex) {
                throw new IllegalArgumentException("Error while parsing date", ex);
            }
        }
    }
}
      
      



,  UTC+03. , 2021-01-21T22:00:00+07:00



,





public class Subscription {

    private LocalDateTime startDate;
  
    // standart getters and setters
}
      
      



@RestController 
public class TestController {
  
  @PostMapping
  public void process(@RequestBody Subscription subscription) {
    //     startDate  subscription   2021-01-21T18:00
  }
}
      
      



. JsonSerializer



, serialize()







null, .





public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (isNull(localDateTime)) {
            return;
        }
        OffsetDateTime timeUtc = localDateTime.atOffset(ZoneOffset.systemDefault().getRules().getOffset(LocalDateTime.now()));
        jsonGenerator.writeString(timeUtc.toString());
    }
}
      
      



? ? . , , , UTC+00. , id . ZoneOffset







, UTC+03, : 2021-02-21T18:00+03:00.



UTC+00, 2021-02-21T18:00Z







Karena kita bekerja dengan sebuah string, tidak akan sulit bagi kita untuk mengubah sedikit kodenya sehingga kita selalu mendapatkan tanggal dalam format yang sama pada keluarannya. Mari kita nyatakan dua konstanta - salah satunya akan sama dengan id default UTC + 00, dan yang kedua - yang ingin kita berikan kepada klien, dan tambahkan tanda centang - jika waktu server berada di zona waktu nol, maka kita akan menggantinya Z



dengan +00:00



. Hasilnya, pembuat serial kami akan terlihat seperti ini





public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

    private static final String UTC_0_OFFSET_ID = "Z";
    private static final String UTC_0_TIMEZONE = "+00:00";

    @Override
    public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (!isNull(localDateTime)) {
            String date;
            OffsetDateTime timeUtc = localDateTime.atOffset(ZoneOffset.systemDefault().getRules().getOffset(LocalDateTime.now()));
            if (UTC_0_OFFSET_ID.equals(timeUtc.getOffset().getId())) {
                date = timeUtc.toString().replace(UTC_0_OFFSET_ID, UTC_0_TIMEZONE);
            } else {
                date = timeUtc.toString();
            }
            jsonGenerator.writeString(date);
        }
    }
}
      
      



Total

Berkat mekanisme pegas bawaan, kami dapat secara otomatis mengonversi tanggal dan waktu dalam format yang diperlukan, tanpa panggilan metode eksplisit apa pun dalam kode.





Kode sumber lengkapnya dapat dilihat di sini








All Articles