Springboot中Instant時間傳參及序列化詳解
Instant時間傳參及序列化
在部分場景中,后臺的時間屬性用的不是Date或Long,而是Instant,Java8引入的一個精度極高的時間類型,可以精確到納秒,但實際使用的時候不需要這么高的精確度,通常到毫秒就可以了。
而在前后端傳參的時候需要對Instant類型進行序列化及反序列化等處理,默認情況下,ObjectMapper是不支持序列化Instant類型的,需要注冊JavaTimeModule才行,而且序列化的結果也不是時間戳,測試如下
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import java.time.Instant; /** * Instant Jackson測試 * * @author yangguirong */ @Slf4j public class InstantTest { ObjectMapper objectMapper = new ObjectMapper(); @Test void serializeTest() throws JsonProcessingException { objectMapper.registerModule(new JavaTimeModule()); String str = objectMapper.writeValueAsString(Instant.now()); log.info("serializeTest: {}", str); // serializeTest: 1691208180.052185000 } @Test void deserializeTest() throws JsonProcessingException { objectMapper.registerModule(new JavaTimeModule()); Instant instant = objectMapper.readValue("1691208180.052185000", Instant.class); log.info("deserializeTest: {}", instant); // deserializeTest: 2023-08-05T04:03:00.052185Z } }
想要將其序列化為毫秒時間戳,需要對序列化及反序列化進行自定義
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.time.Instant; /** * 自定義Instant序列化及反序列 * * @author yangguirong */ public class InstantMillsTimeModule extends SimpleModule { public InstantMillsTimeModule() { this.addSerializer(Instant.class, new InstantMillisecondsSerializer()); this.addDeserializer(Instant.class, new InstantMillisecondsDeserializer()); } public static class InstantMillisecondsSerializer extends JsonSerializer<Instant> { @Override public void serialize(Instant instant, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (instant == null) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(instant.toEpochMilli()); } } } @Slf4j public static class InstantMillisecondsDeserializer extends JsonDeserializer<Instant> { @Override public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { try { long mills = p.getValueAsLong(); return mills > 0 ? Instant.ofEpochMilli(mills) : null; } catch (Exception e) { log.error("Instant類型反序列化失??!val: {}, message: {}", p.getText(), e.getMessage()); } return null; } } }
再來測試一下自定義的序列化及反序列化方式
import com.example.websocket.config.InstantMillsTimeModule; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import java.time.Instant; /** * Instant Jackson測試 * * @author yangguirong */ @Slf4j public class InstantTest { ObjectMapper objectMapper = new ObjectMapper(); @Test void serializeTest() throws JsonProcessingException { objectMapper.registerModule(new JavaTimeModule()); String str = objectMapper.writeValueAsString(Instant.now()); log.info("serialize: {}", str); // serialize: 1691208180.052185000 } @Test void deserializeTest() throws JsonProcessingException { objectMapper.registerModule(new JavaTimeModule()); Instant instant = objectMapper.readValue("1691208180.052185000", Instant.class); log.info("deserialize: {}", instant); // deserialize: 2023-08-05T04:03:00.052185Z } @Test void millsSerializeTest() throws JsonProcessingException { objectMapper.registerModule(new InstantMillsTimeModule()); String str = objectMapper.writeValueAsString(Instant.now()); log.info("millsSerializeTest: {}", str); // millsSerializeTest: 1691208541018 } @Test void millsDeserializeTest() throws JsonProcessingException { objectMapper.registerModule(new InstantMillsTimeModule()); Instant instant = objectMapper.readValue("1691208541018", Instant.class); log.info("millsDeserializeTest: {}", instant); // deserialize: 2023-08-05T04:09:01.018Z } }
可以看到,結果是符合預期的,可以在毫秒時間戳和Instant之間相互轉換。
在后臺配置SpringBoot的時候,需要考慮兩種情況,一種就是Instant作為RequestParam/PathVariable的情況,另一種是RequestBody/ResponseBody的情況。前者借助轉換器實現,配置如下
import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; import org.springframework.format.FormatterRegistry; import org.springframework.util.StringUtils; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.time.Instant; /** * web mvc設置 * * @author yangguirong */ @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(instantConvert()); } public Converter<String, Instant> instantConvert() { // 不能替換為lambda表達式 return new Converter<String, Instant>() { @Override public Instant convert(String source) { if (StringUtils.hasText(source)) { return Instant.ofEpochMilli(Long.parseLong(source)); } return null; } }; } }
后者如果是局部配置,則在具體的實體類屬性上添加@JsonSerialize和@JsonDeserialize注解,在注解中指定序列化器和反序列化器即可。如果是全局配置,則可以按照如下方式進行配置,將InstantMillsTimeModule注冊為Bean,這個Bean會在JacksonAutoConfiguration中的StandardJackson2ObjectMapperBuilderCustomizer被自動注入,然后進行注冊。
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Jackson配置 * * @author yangguirong */ @Configuration @AutoConfigureBefore(JacksonAutoConfiguration.class) public class JacksonCustomizerConfig { @Bean public Jackson2ObjectMapperBuilderCustomizer jacksonModuleRegistryCustomizer() { return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.featuresToDisable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, SerializationFeature.FAIL_ON_EMPTY_BEANS ); } @Bean public InstantMillsTimeModule instantMillsTimeModule() { return new InstantMillsTimeModule(); } }
簡單的接口測試
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.time.Instant; /** * instant測試 * * @author yangguirong */ @Slf4j @RequestMapping("instant") @RestController public class InstantTestController { @GetMapping("getInstant") public Instant getInstant() { return Instant.now(); } @PutMapping("setInstant") public void setInstant(@RequestParam Instant instant) { log.info("setInstant: {}", instant); } @GetMapping("getInstantDemoVO") public DemoVO getInstantDemoVO() { return new DemoVO(Instant.now()); } @PutMapping("setInstantDemoVO") public void setInstantDemoVO(@RequestBody DemoVO vo) { log.info("setInstantDemoVO:{}", vo); } @Data @NoArgsConstructor @AllArgsConstructor static class DemoVO { private Instant instant; } }
到此這篇關于Springboot中Instant時間傳參及序列化詳解的文章就介紹到這了,更多相關Instant時間傳參及序列化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mybatis plus CU自動填充 和 軟刪除自動填充的實現方法
這篇文章主要介紹了mybatis plus CU自動填充 和 軟刪除自動填充的實現方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07Spring Boot 與 Kotlin 使用JdbcTemplate連接MySQL數據庫的方法
本文介紹在Spring Boot基礎下配置數據源和通過 JdbcTemplate 編寫數據訪問的示例。感興趣的朋友跟隨腳本之家小編一起學習吧2018-01-01