You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter DateTime与Spring Boot LocalDateTime适配:忽略毫秒的处理方案咨询

解决Spring Boot接收可变毫秒位数LocalDateTime的问题

问题核心

客户端发送的时间字符串包含可变位数的毫秒(.SS/.SSS/.SSSS等),服务端需要将其解析为秒级精度的LocalDateTime,直接使用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")会因格式不匹配抛出解析异常。


方案1:自定义字段级反序列化器

针对单个DTO字段定制解析逻辑,既兼容可变毫秒位数,又自动截断到秒级精度。

  1. 编写自定义反序列化器:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class TruncatedLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    // 定义兼容1-9位毫秒/纳秒的格式化器
    private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
            .appendPattern("yyyy-MM-dd HH:mm:ss")
            .optionalStart()
            .appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, true)
            .optionalEnd()
            .toFormatter();

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String dateStr = p.getText().trim();
        LocalDateTime dateTime = LocalDateTime.parse(dateStr, FORMATTER);
        return dateTime.withNano(0); // 截断毫秒,保留秒级精度
    }
}
  1. 在DTO字段上应用该反序列化器:
public class YourRequestDTO {
    @JsonDeserialize(using = TruncatedLocalDateTimeDeserializer.class)
    private LocalDateTime targetDateTime;

    // Getter & Setter
}

方案2:全局Jackson配置

如果需要所有LocalDateTime类型都采用相同的解析规则,可以全局配置Jackson:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

@Configuration
public class JacksonGlobalConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule timeModule = new JavaTimeModule();

        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd HH:mm:ss")
                .optionalStart()
                .appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, true)
                .optionalEnd()
                .toFormatter();

        // 替换默认反序列化器,添加截断毫秒逻辑
        timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter) {
            @Override
            public LocalDateTime deserialize(com.fasterxml.jackson.core.JsonParser p, DeserializationContext ctxt) throws IOException {
                LocalDateTime dateTime = super.deserialize(p, ctxt);
                return dateTime.withNano(0);
            }
        });

        objectMapper.registerModule(timeModule);
        return objectMapper;
    }
}

方案3:简化版(依赖Setter截断)

如果不想编写自定义序列化器,也可以结合@JsonFormat的宽松模式+Setter手动截断:

public class YourRequestDTO {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", lenient = OptBoolean.TRUE)
    private LocalDateTime targetDateTime;

    public void setTargetDateTime(LocalDateTime targetDateTime) {
        this.targetDateTime = targetDateTime.withNano(0); // 手动截断毫秒
    }

    // Getter
}

注意:这种方式依赖Jackson的宽松解析规则,兼容性不如前两种方案,仅适合简单场景。


内容的提问来源于stack exchange,提问作者Demir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:27:38