Springboot中Instant時(shí)間傳參及序列化詳解
Instant時(shí)間傳參及序列化
在部分場景中,后臺的時(shí)間屬性用的不是Date或Long,而是Instant,Java8引入的一個(gè)精度極高的時(shí)間類型,可以精確到納秒,但實(shí)際使用的時(shí)候不需要這么高的精確度,通常到毫秒就可以了。
而在前后端傳參的時(shí)候需要對Instant類型進(jìn)行序列化及反序列化等處理,默認(rèn)情況下,ObjectMapper是不支持序列化Instant類型的,需要注冊JavaTimeModule才行,而且序列化的結(jié)果也不是時(shí)間戳,測試如下
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
}
}
想要將其序列化為毫秒時(shí)間戳,需要對序列化及反序列化進(jìn)行自定義
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
}
}
可以看到,結(jié)果是符合預(yù)期的,可以在毫秒時(shí)間戳和Instant之間相互轉(zhuǎn)換。
在后臺配置SpringBoot的時(shí)候,需要考慮兩種情況,一種就是Instant作為RequestParam/PathVariable的情況,另一種是RequestBody/ResponseBody的情況。前者借助轉(zhuǎn)換器實(shí)現(xiàn),配置如下
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設(shè)置
*
* @author yangguirong
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(instantConvert());
}
public Converter<String, Instant> instantConvert() {
// 不能替換為lambda表達(dá)式
return new Converter<String, Instant>() {
@Override
public Instant convert(String source) {
if (StringUtils.hasText(source)) {
return Instant.ofEpochMilli(Long.parseLong(source));
}
return null;
}
};
}
}
后者如果是局部配置,則在具體的實(shí)體類屬性上添加@JsonSerialize和@JsonDeserialize注解,在注解中指定序列化器和反序列化器即可。如果是全局配置,則可以按照如下方式進(jìn)行配置,將InstantMillsTimeModule注冊為Bean,這個(gè)Bean會在JacksonAutoConfiguration中的StandardJackson2ObjectMapperBuilderCustomizer被自動注入,然后進(jìn)行注冊。
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;
}
}
到此這篇關(guān)于Springboot中Instant時(shí)間傳參及序列化詳解的文章就介紹到這了,更多相關(guān)Instant時(shí)間傳參及序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot項(xiàng)目中后端接收前端傳參的方法示例詳解
- springboot通過spel結(jié)合aop實(shí)現(xiàn)動態(tài)傳參的案例
- springboot前端傳參date類型后臺處理的方式
- SpringBoot通過@MatrixVariable進(jìn)行傳參詳解
- SpringBoot使用MyBatis時(shí)的幾種傳參規(guī)范示例
- springboot 傳參校驗(yàn)@Valid及對其的異常捕獲方式
- SpringBoot多種場景傳參模式
- Docker如何給Springboot項(xiàng)目動態(tài)傳參的實(shí)現(xiàn)方法
- Springboot傳參詳解
相關(guān)文章
mybatis plus CU自動填充 和 軟刪除自動填充的實(shí)現(xiàn)方法
這篇文章主要介紹了mybatis plus CU自動填充 和 軟刪除自動填充的實(shí)現(xiàn)方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
Spring Boot 與 Kotlin 使用JdbcTemplate連接MySQL數(shù)據(jù)庫的方法
本文介紹在Spring Boot基礎(chǔ)下配置數(shù)據(jù)源和通過 JdbcTemplate 編寫數(shù)據(jù)訪問的示例。感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-01-01
Mybatis中的mapper是如何和XMl關(guān)聯(lián)起來的
這篇文章主要介紹了Mybatis中的mapper是如何和XMl關(guān)聯(lián)起來的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
IntelliJ IDEA全局內(nèi)容搜索和替換教程圖解
很多朋友在做項(xiàng)目時(shí),會在整個(gè)項(xiàng)目里活指定文件夾下進(jìn)行全局搜索和替換,下面小編給大家?guī)砹薎ntelliJ IDEA全局內(nèi)容搜索和替換教程圖解,需要的朋友參考下吧2018-04-04
java集合與數(shù)組的相同點(diǎn)和不同點(diǎn)
今天小編就為大家分享一篇關(guān)于java集合與數(shù)組的相同點(diǎn)和不同點(diǎn),小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-04-04
Java實(shí)現(xiàn)多路復(fù)用select模型實(shí)例詳解
在計(jì)算機(jī)網(wǎng)絡(luò)中,多路復(fù)用(Multiplexing)指的是通過一種機(jī)制將多個(gè) I/O 操作合并到同一個(gè)線程或進(jìn)程中,從而提高系統(tǒng)的效率,在 Java 中,可以使用 Selector 類來實(shí)現(xiàn)基于 I/O 多路復(fù)用的模式,故本文給大家介紹了Java實(shí)現(xiàn)多路復(fù)用select模型實(shí)例,需要的朋友可以參考下2025-03-03

