Spring Boot 统一处理前后台传输时间格式统一问题 (时间戳)

本贴最后更新于 524 天前,其中的信息可能已经水流花落

1.统一处理前端传入时间戳

1.使用 LocalDateDeserializer 对前端传入的时间戳格式进行统一反序列成 LocalDate
/** * 扩展jackson反序列, 使其支持时间戳转LocalDate * * @author: mxj */ public class LocalDateExtDeserializer extends LocalDateDeserializer { public LocalDateExtDeserializer() { super(DateTimeFormatter.ISO_LOCAL_DATE); } public LocalDateExtDeserializer(DateTimeFormatter dtf) { super(dtf); } @Override protected JsonDeserializer<LocalDate> withDateFormat(DateTimeFormatter formatter) { return new LocalDateExtDeserializer(formatter); } @Override public LocalDate deserialize(JsonParser parse, DeserializationContext context) throws IOException { if (parse.hasToken(JsonToken.VALUE_NUMBER_INT)) { return LocalDateTime.ofInstant(Instant.ofEpochMilli(parse.getLongValue()), ZoneId.systemDefault()).toLocalDate(); } return super.deserialize(parse, context); } }
2.使用 LocalDateTimeDeserializer 对前端传输的时间戳格式进行统一反序列成 LocalDateTime 类型
/** * 扩展jackson反序列, 使其支持时间戳转LocalDateTime * * @author: mxj */ public class LocalDateTimeExtDeserializer extends LocalDateTimeDeserializer { public LocalDateTimeExtDeserializer() { super(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } public LocalDateTimeExtDeserializer(DateTimeFormatter formatter) { super(formatter); } @Override protected JsonDeserializer<LocalDateTime> withDateFormat(DateTimeFormatter formatter) { return new LocalDateTimeExtDeserializer(formatter); } @Override public LocalDateTime deserialize(JsonParser parse, DeserializationContext context) throws IOException { if (parse.hasToken(JsonToken.VALUE_NUMBER_INT)) { return LocalDateTime.ofInstant(Instant.ofEpochMilli(parse.getLongValue()), ZoneId.systemDefault()); } return super.deserialize(parse, context); } }

2.统一处理后台返回给前端时间格式问题(时间戳)

1.使用 LocalDateSerializerh 对后端接口中 LocalDate 类型返回给前端时间进行统一序列化成时间戳
package com.cell.jackson.serializer; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import java.io.IOException; import java.time.LocalDate; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; /** * 将LocalDate转为时间戳 * * @author: mxj */ public class LocalDateExtSerializer extends LocalDateSerializer { private final Boolean writeDatesAsTimestamps; public LocalDateExtSerializer(Boolean writeDatesAsTimestamps) { super(DateTimeFormatter.ISO_LOCAL_DATE); this.writeDatesAsTimestamps = writeDatesAsTimestamps; } protected LocalDateExtSerializer(LocalDateSerializer base, Boolean useTimestamp, DateTimeFormatter dtf, JsonFormat.Shape shape, Boolean writeDatesAsTimestamps) { super(base, useTimestamp, dtf, shape); this.writeDatesAsTimestamps = writeDatesAsTimestamps; } @Override protected LocalDateSerializer withFormat(Boolean useTimestamp, DateTimeFormatter dtf, JsonFormat.Shape shape) { return new LocalDateExtSerializer(this, useTimestamp, dtf, shape, writeDatesAsTimestamps); } @Override public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (writeDatesAsTimestamps) { jsonGenerator.writeNumber(localDate.atStartOfDay(ZoneOffset.systemDefault()).toInstant().toEpochMilli()); } else { super.serialize(localDate, jsonGenerator, serializerProvider); } } }
2.使用 LocalDateTimeSerializer 对后端接口中 LocalDateTime 类型返回给前端时间进行统一序列化成时间戳
package com.cell.jackson.serializer; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import java.io.IOException; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; /** * 将LocalDateTime转为时间戳 * * @author: mxj */ public class LocalDateTimeExtSerializer extends LocalDateTimeSerializer { private final Boolean writeDatesAsTimestamps; public LocalDateTimeExtSerializer(Boolean writeDatesAsTimestamps) { super(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); this.writeDatesAsTimestamps = writeDatesAsTimestamps; } protected LocalDateTimeExtSerializer(DateTimeFormatter f, Boolean writeDatesAsTimestamps) { super(f); this.writeDatesAsTimestamps = writeDatesAsTimestamps; } @Override protected LocalDateTimeSerializer withFormat(Boolean useTimestamp, DateTimeFormatter f, JsonFormat.Shape shape) { return new LocalDateTimeExtSerializer(f, writeDatesAsTimestamps); } @Override public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (writeDatesAsTimestamps) { jsonGenerator.writeNumber(localDateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli()); } else { super.serialize(localDateTime, jsonGenerator, serializerProvider); } } }

3.WebMvcConfigurer 配置 RequestBody 内容转换器

1.配置好以上两步后,要在 WebMvcConfigurer 配置类中进行增加 RequestBody 内容转换器(缺点就是只针对于 Controller 层中的接中 @RequestBody 注解中的参数生效,解决方案在后头)
/** * WebMvcConfig * * @author: mxj * @Date 2023/1/28 11:29 */ @ConditionalOnClass(WebMvcConfigurer.class) public class WebMvcConfiguration implements WebMvcConfigurer { /** * 增加了Jackson对Jdk8Time的支持 * * @param converters RequestBody内容转换器列表, 这里只需要对jackson提供的转换器进行拦截 */ public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter<?> converter : converters) { if (MappingJackson2HttpMessageConverter.class.isAssignableFrom(converter.getClass())) { ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper(); SimpleModule dateModule = new SimpleModule(); //jackson序列化 dateModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); dateModule.addSerializer(LocalDate.class, new LocalDateExtSerializer(true)); dateModule.addSerializer(LocalDateTime.class, new LocalDateTimeExtSerializer(true)); //jackson反序列化, 默认的格式为 yyyy-MM-ddTHH:mm:ss, 故需要配置 dateModule.addDeserializer(LocalDate.class, new LocalDateExtDeserializer()); dateModule.addDeserializer(LocalDateTime.class, new LocalDateTimeExtDeserializer()); objectMapper.registerModule(dateModule); } } } }

4.解决掉 @PathVariable 与 @RequestParam 等注解的接收参数时间转换问题

1.以 LongLocalDateTime 为例子,利用 Converter 将前端传的时间戳格式转换为 java 对应的 LocalDateTime 对象
package com.cell.converter; import com.cell.converter.handler.localDateTime.LocalDateTimeConverterHandler; import com.cell.converter.handler.localDateTime.LongLocalDateTimeConverter; import com.cell.converter.handler.localDateTime.StringLocalDateTimeConverter; import com.cell.webExport.config.response.exception.BusinessException; import lombok.extern.slf4j.Slf4j; import org.springframework.core.convert.converter.Converter; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; /** * 统一转换成LocalDateTime * * @Author MXJ */ @Slf4j public class LocalDateTimeConverter implements Converter<String, LocalDateTime> { private static List<LocalDateTimeConverterHandler> localDateTimeConverterHandlerList = new ArrayList<>(); static { //可以配置多种类型格式解释(这理配置了两种格式) localDateTimeConverterHandlerList.add(new StringLocalDateTimeConverter()); localDateTimeConverterHandlerList.add(new LongLocalDateTimeConverter()); } @Override public LocalDateTime convert(String source) { for (LocalDateTimeConverterHandler item : localDateTimeConverterHandlerList) { try { return item.getLocalDateTime(source); } catch (Exception e) { log.info("LocalDateTime时间格式解释失败"); } } throw new BusinessException("LocalDateTime时间格式解释失败"); } }
package com.cell.converter.handler.localDateTime; import java.time.LocalDateTime; /** * 解释类型接口 * * @Author MXJ */ public interface LocalDateTimeConverterHandler { /** * 获取LocalDateTime */ LocalDateTime getLocalDateTime(String source); }
package com.cell.converter.handler.localDateTime; import lombok.extern.slf4j.Slf4j; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; /** * LocalDateTime时间戳类型(根据时间戳解释成LocalDateTime) * * @Author MXJ */ @Slf4j public class LongLocalDateTimeConverter implements LocalDateTimeConverterHandler { /** * 获取LocalDateTime */ @Override public LocalDateTime getLocalDateTime(String source) { Instant instant = Instant.ofEpochMilli(Long.parseLong(source)); return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); } }
package com.cell.converter.handler.localDateTime; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * LocalDateTime字符串类型 * @Author MXJ */ public class StringLocalDateTimeConverter implements LocalDateTimeConverterHandler{ /** * 获取LocalDateTime(不同种格式) * @param source * @return */ @Override public LocalDateTime getLocalDateTime(String source) { try { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yy-M-d ah:mm"); return LocalDateTime.parse(source, formatter); }catch (Exception e){ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); return LocalDateTime.parse(source, formatter); } } }

5.以上就是统一实现前后端时间格式问题(请大家多多指教)

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    948 引用 • 1460 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...