SpringBoot全局时间格式统一处理和灵活处理

封装配置类

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.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 基于Jackson对象映射器生成器定制器
 */
@Configuration
public class JacksonObjectMapperCustomizer implements Jackson2ObjectMapperBuilderCustomizer {

    public static final DateTimeFormatter YEAR_MONTH = DateTimeFormatter.ofPattern("yyyy-MM");
    public static final DateTimeFormatter LOCAL_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter HOUR_MINUTE = DateTimeFormatter.ofPattern("HH:mm");
    public static final DateTimeFormatter LOCAL_TIME = DateTimeFormatter.ofPattern("HH:mm:ss");
    public static final DateTimeFormatter LOCAL_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static final Pattern yyyy_MM = Pattern.compile("\\d{4}-\\d{2}");
    public static final Pattern yyyy_MM_dd = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
    public static final Pattern HH_mm = Pattern.compile("([0-1]?[0-9]|2[0-3]):([0-5][0-9])");
    public static final Pattern HH_mm_ss = Pattern.compile("([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])");
    public static final Pattern yyyy_MM_dd_HH_mm_ss = Pattern.compile("\\d{4}-\\d{2}-\\d{2}([ ])([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])");

    @Override
    public void customize(Jackson2ObjectMapperBuilder builder) {
        // LocalDateTime序列化、反序列化
        builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(LOCAL_DATE_TIME));
        builder.deserializerByType(LocalDateTime.class, new FlexibleLocalDateTimeDeserializer(LOCAL_DATE_TIME));
        // LocalDate序列化、反序列化
        builder.serializerByType(LocalDate.class, new LocalDateSerializer(LOCAL_DATE));
        builder.deserializerByType(LocalDate.class, new FlexibleLocalDateDeserializer(LOCAL_DATE));
        // LocalTime序列化、反序列化
        builder.serializerByType(LocalTime.class, new LocalTimeSerializer(LOCAL_TIME));
        builder.deserializerByType(LocalTime.class, new FlexibleLocalTimeDeserializer(LOCAL_TIME));
        // Long序列化(序列化成字符串,因为精度问题,前端拿到数字类型会丢失精度)
        builder.serializerByType(Long.class, ToStringSerializer.instance);
    }


    /**
     * 灵活的LocalDateTime反序列化
     * 支持格式: yyyy-MM-dd HH:mm:ss, yyyy-MM-dd, yyyy-MM
     */
    public static class FlexibleLocalDateTimeDeserializer extends LocalDateTimeDeserializer {

        private FlexibleLocalDateTimeDeserializer() {
            this(LOCAL_DATE_TIME);
        }

        public FlexibleLocalDateTimeDeserializer(DateTimeFormatter formatter) {
            super(formatter);
        }

        @Override
        public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
            String timeStr = parser.getText();
            if (timeStr == null || (timeStr = timeStr.trim()).isEmpty()) return null;
            else if (yyyy_MM_dd_HH_mm_ss.matcher(timeStr).matches())
                return super.deserialize(parser, context);
            else if (yyyy_MM_dd.matcher(timeStr).matches())
                return parser.getCurrentName().toLowerCase().contains("end") ? LocalDate.parse(timeStr, LOCAL_DATE).atTime(LocalTime.MAX) : LocalDate.parse(timeStr, LOCAL_DATE).atStartOfDay();
            else if (yyyy_MM.matcher(timeStr).matches())
                return parser.getCurrentName().toLowerCase().contains("end") ? YearMonth.parse(timeStr, YEAR_MONTH).atEndOfMonth().atTime(LocalTime.MAX) : YearMonth.parse(timeStr, YEAR_MONTH).atDay(1).atStartOfDay();
            else throw new DateTimeParseException("时间字符串【" + timeStr + "'】格式不正确", timeStr, 0);
        }
    }

    /**
     * 灵活的LocalDate反序列化
     * 支持格式: yyyy-MM-dd HH:mm:ss, yyyy-MM-dd, yyyy-MM
     */
    public static class FlexibleLocalDateDeserializer extends LocalDateDeserializer {

        private FlexibleLocalDateDeserializer() {
            this(LOCAL_DATE);
        }

        public FlexibleLocalDateDeserializer(DateTimeFormatter dtf) {
            super(dtf);
        }

        @Override
        public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
            String timeStr = parser.getText();
            if (timeStr == null || (timeStr = timeStr.trim()).isEmpty()) return null;
            else if (yyyy_MM_dd.matcher(timeStr).find())
                return timeStr.length() > 10 ? LocalDateTime.parse(timeStr, LOCAL_DATE_TIME).toLocalDate() : LocalDate.parse(timeStr, LOCAL_DATE);
            else if (yyyy_MM.matcher(timeStr).matches())
                return parser.getCurrentName().toLowerCase().contains("end") ? YearMonth.parse(timeStr, YEAR_MONTH).atEndOfMonth() : YearMonth.parse(timeStr, YEAR_MONTH).atDay(1);
            else throw new DateTimeParseException("时间字符串【" + timeStr + "'】格式不正确", timeStr, 0);
        }
    }

    /**
     * 灵活的LocalTime反序列化
     * 支持格式: HH:mm:ss, HH:mm
     */
    public static class FlexibleLocalTimeDeserializer extends LocalTimeDeserializer {

        private FlexibleLocalTimeDeserializer() {
            this(LOCAL_TIME);
        }

        public FlexibleLocalTimeDeserializer(DateTimeFormatter formatter) {
            super(formatter);
        }

        @Override
        public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
            String timeStr = parser.getText();
            if (timeStr == null || (timeStr = timeStr.trim()).isEmpty()) return null;
            else if (HH_mm_ss.matcher(timeStr).matches()) return super.deserialize(parser, context);
            else if (HH_mm.matcher(timeStr).matches()) return LocalTime.parse(timeStr, HOUR_MINUTE);
            else throw new DateTimeParseException("时间字符串【" + timeStr + "'】格式不正确", timeStr, 0);
        }
    }

    /**
     * 年月日序列化
     * 支持类型: LocalDateTime, LocalDate
     */
    public static class LocalDateFormatSerializer extends JsonSerializer<TemporalAccessor> {

        @Override
        public void serialize(TemporalAccessor temporalAccessor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (Objects.isNull(temporalAccessor)) return;
            jsonGenerator.writeString(LOCAL_DATE.format(temporalAccessor));
        }
    }

    /**
     * 年月序列化
     * 支持类型: LocalDateTime, LocalDate, YearMonth
     */
    public static class YearMonthFormatSerializer extends JsonSerializer<TemporalAccessor> {

        @Override
        public void serialize(TemporalAccessor temporalAccessor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (Objects.isNull(temporalAccessor)) return;
            jsonGenerator.writeString(YEAR_MONTH.format(temporalAccessor));
        }
    }

    /**
     * 时分序列化
     * 支持类型: LocalDateTime, LocalTime
     */
    public static class HourMinuteFormatSerializer extends JsonSerializer<TemporalAccessor> {

        @Override
        public void serialize(TemporalAccessor temporalAccessor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (Objects.isNull(temporalAccessor)) return;
            jsonGenerator.writeString(HOUR_MINUTE.format(temporalAccessor));
        }
    }

    /**
     * 时分秒序列化
     * 支持类型: LocalDateTime, LocalTime
     */
    public static class LocalTimeFormatSerializer extends JsonSerializer<TemporalAccessor> {

        @Override
        public void serialize(TemporalAccessor temporalAccessor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (Objects.isNull(temporalAccessor)) return;
            jsonGenerator.writeString(LOCAL_TIME.format(temporalAccessor));
        }
    }
}

灵活处理LocalDateTime类型

	// 入参格式: yyyy-MM-dd HH:mm:ss, yyyy-MM-dd, yyyy-MM
    @JsonDeserialize(using = JacksonObjectMapperCustomizer.FlexibleLocalDateTimeDeserializer.class)
    // 出参格式(默认): yyyy-MM-dd HH:mm:ss
    // 出参格式: yyyy-MM-dd
    // @JsonSerialize(using = JacksonObjectMapperCustomizer.LocalDateFormatSerializer.class)
    // 出参格式: yyyy-MM
    // @JsonSerialize(using = JacksonObjectMapperCustomizer.YearMonthFormatSerializer.class)
    private LocalDateTime startTime;

灵活处理LocalDate类型

	// 入参格式: yyyy-MM-dd HH:mm:ss, yyyy-MM-dd, yyyy-MM
    @JsonDeserialize(using = JacksonObjectMapperCustomizer.FlexibleLocalDateDeserializer.class)
    // 出参格式(默认): yyyy-MM-dd
    // 出参格式: yyyy-MM
    // @JsonSerialize(using = JacksonObjectMapperCustomizer.YearMonthFormatSerializer.class)
    private LocalDate startTime;

灵活处理LocalTime类型

	// 入参格式:HH:mm:ss, HH:mm
    @JsonDeserialize(using = JacksonObjectMapperCustomizer.FlexibleLocalTimeDeserializer.class)
    // 出参格式(默认): HH:mm:ss
    // 出参格式: HH:mm
    @JsonSerialize(using = JacksonObjectMapperCustomizer.HourMinuteFormatSerializer.class)
    private LocalTime startTime;

命名小细节

当变量名不包含end字符串时, 默认填充起始时间, 反之填充最大时间,

小结

时间处理封装的并不算彻底, 但足够解决大部分需求, 封装不一定越多越好, 实用就行。
如不满足业务需求, 可自行扩展。
如有不完善的地方或错误, 请评论点出或联系我及时纠正, 谢谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值