spring mvc 接收 时间戳转 LocalDateTime

本文详细介绍了如何在Spring MVC中通过自定义注解@TimeStampFormat,实现GET请求中Long类型的时间戳转换为LocalDateTime,并展示了POST请求中如何处理@RequestBody。涉及到了AnnotationFormatterFactory、Converter和JsonSerializer/JsonDeserializer的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring mvc 接收 时间戳(Long)转 LocalDateTime

默认情况下,spring mvc 只接收 string 类型转成 LocalDateTime, 现要求 接收Long 类型时间戳要转成LocalDateTime, 又不想全局统一转,参照 @NumberFormat 实现 GET 请求接收 Long 转成 LocalDateTime

处理GET 请求

  • RequestParamMethodArgumentResolver
    • DataBinder
      • ConversionService (如果配置了的话)
        • GenericConversionService
          • Converter (如果配置了的话)
            • AnnotationFormatterFactory (注解方式)

可以发现 ,GET 请求接收前端参数是通过 Converter 来转换, 不过 这是统一处理的,如果要通过注解方式指定转换呢?

可以通过 AnnotationFormatterFactory 来实现

定义TimeStampFormat

/**
 * 处理 GET 请求 timestamp 转成 LocalDateTime
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface TimeStampFormat {
}

对指定注解 类型解析

public class TimeStampToLocalDateTimeAnnotationFormatterFactory extends EmbeddedValueResolutionSupport
        implements AnnotationFormatterFactory<TimeStampFormat> {

    private static final Set<Class<?>> FIELD_TYPES;

    static {
        // Create the set of field types that may be annotated with @DateTimeFormat.
        Set<Class<?>> fieldTypes = new HashSet<>(1);
        fieldTypes.add(LocalDateTime.class);
        FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
    }

    @Override
    public final Set<Class<?>> getFieldTypes() {
        return FIELD_TYPES;
    }

    @Override
    public Printer<LocalDateTime> getPrinter(TimeStampFormat annotation, Class<?> fieldType) {
        return new LongToLocalDateTimeParser();
    }

    @Override
    @SuppressWarnings("unchecked")
    public Parser<LocalDateTime> getParser(TimeStampFormat annotation, Class<?> fieldType) {
        return new LongToLocalDateTimeParser();
    }

    class LongToLocalDateTimeParser implements Formatter<LocalDateTime> {
        @Override
        public LocalDateTime parse(String text, Locale locale) throws ParseException {
            return Instant
                    .ofEpochMilli(Long.parseLong(text))
                    .atZone(ZoneOffset.ofHours(8))
                    .toLocalDateTime();
        }

        @Override
        public String print(LocalDateTime object, Locale locale) {
            return object.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + "";
        }
    }

}

向容器注册

@Configuration
public class CusWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldAnnotation(new TimeStampToLocalDateTimeAnnotationFormatterFactory());
    }
}

dto:

@Data
public class UserDto {
    /**
     * GET 请求处理
     */
    @TimeStampFormat
    @JsonSerialize(using = LocalDateTimeToLongSerializer.class)
    private LocalDateTime jsonFormatDateTime;
}

测试 :

@GetMapping("/test")
public UserDto userDto(UserDto query, @TimeStampFormat LocalDateTime paramTime) throws JsonProcessingException {
    log.info(">>>request: {}", objectMapper.writeValueAsString(query));
    UserDto userDto = new UserDto();
    userDto.setDateTime(LocalDateTime.now());
    userDto.setJsonFormatDateTime(LocalDateTime.now());
    return userDto;
}

处理 POST 请求 @RequestBody

  • RequestParamMethodArgumentResolver
    • RequestResponseBodyMethodProcessor
      • HttpMessageConverter
        • GenericHttpMessageConverter
          • AbstractJackson2HttpMessageConverter
            • ObjectMapper

可以发现,@RequestBody最终交给 AbstractJackson2HttpMessageConverter (spring 默认), 而 AbstractJackson2HttpMessageConverter 交给 ObjectMapper 来序列化和反序列化

转时间戳

public class LocalDateTimeToLongSerializer extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    }
}

时间戳转 LocalDateTime

public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    @Override
    public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        if (StrUtil.isEmpty(jsonParser.getText())) {
            return null;
        }
        return Instant
                .ofEpochMilli(Long.parseLong(jsonParser.getText()))
                .atZone(ZoneOffset.ofHours(8))
                .toLocalDateTime();
    }

}

dto:

@Data
public class UserDto {

    /**
     * POST 处理
     */
    @JsonSerialize(using = LocalDateTimeToLongSerializer.class)
    @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
    private LocalDateTime dateTime;

}

测试:

@PostMapping("/test2")
public UserDto userDto2(@RequestBody UserDto query) throws JsonProcessingException {

    log.info(">>>request: {}", objectMapper.writeValueAsString(query));
    UserDto userDto = new UserDto();
    userDto.setDateTime(LocalDateTime.now());
    return userDto;
}

good luck!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值