Java controller接口出入参时间序列化转换操作方法(两种)

 更新时间:2025年04月30日 11:58:17   作者:Muscleheng  
这篇文章主要介绍了Java controller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看看吧

场景:在controller编写的接口,在前后端交互过程中一般都会涉及到时间字段的交互,比如:后端给前端返的数据有时间相关的字段,同样,前端也存在传时间相关的字段给后端,最原始的方式就是前后端都先转换成字符串和时间戳后进行传输,收到后再进行转换,特别麻烦。
为了方便可以使用注解或者配置做到时间字段的自动转换,这里列举两种简单的操作。

方式一、使用注解

就是在日期字段上添加对应的注解(@JsonFormat),例:

    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime2;
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime3;

优点:灵活、清晰。
缺点:所有需要转换的字段都需要手动添加、并且只支持时间和指定格式字符串互转,不支持时间戳

方式二、统一配置

一劳永逸的方式,支持时间和 时间戳、字符串 之间的互转

package com.zhh.demo.config;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
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.ser.std.ToStringSerializer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@Configuration
// 表示通过aop框架暴露该代理对象,AopContext能够访问
//@EnableAspectJAutoProxy(exposeProxy = true)
public class ApplicationConfig {
    /** 年-月-日 时:分:秒 */
    private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /**
     * 序列化 时间格式转换类型
     * timestamp:时间戳
     * dateString: 时间字符串格式
     * */
    private static final String LOCAL_DATE_TIME_SERIALIZER_TYPE = "dateString";
    /**
     * description:适配自定义序列化和反序列化策略
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            // 时间的序列化和反序列化
            builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer());
            builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer());
            // 将long类型数据转化为string给前端 避免前端造成的精度丢失
            builder.serializerByType(Long.class, ToStringSerializer.instance);
            builder.serializerByType(BigInteger.class, ToStringSerializer.instance);
        };
    }
    /**
     * description:序列化
     * LocalDateTime序列化为毫秒级时间戳
     */
    public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            if (value != null) {
                // 通过配置决定把时间转换成 时间戳 或 时间字符串
                if ("timestamp".equals(LOCAL_DATE_TIME_SERIALIZER_TYPE)) {
                    // 13位时间戳
                    gen.writeNumber(LocalDateTimeUtil.toEpochMilli(value));
                } else {
                    // 指定格式的时间字符串
                    gen.writeString(value.format(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
                }
            }
        }
    }
    /**
     * description:反序列化
     * 毫秒级时间戳序列化为LocalDateTime
     */
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
                throws IOException {
            //2023年11月2日: 尝试反序列增加更多的支持, 支持long输入, 支持字符串输入
            if (p == null) {
                return null;
            }
            String source = p.getText();
            return parse(source);
        }
    }
    /**
     * 时间戳字符串或格式化时间字符串转换为 LocalDateTime
     * 例:1745806578000、2025-04-28 10:16:18
     * @param source    13位时间戳 或格式化时间字符串
     * @return
     */
    private static LocalDateTime parse(String source) {
        // 如果是时间戳
        if (NumberUtil.isLong(source)) {
            long timestamp = Long.parseLong(source);
            if (timestamp > 0) {
                return LocalDateTimeUtil.of(timestamp, ZoneOffset.of("+8"));
            } else {
                return null;
            }
            // 如果是格式化时间字符串
        } else {
            if (StringUtils.isBlank(source)) {
                return null;
            }
            // 尝试判断能否解析
            if (canParseByDateTimeFormatter(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) {
                return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT));
            }
            return null;
        }
    }
    /**
     * 判断是否能解析格式化时间字符串
     * @param source    格式化时间字符串(格式 2025-04-28 10:16:18)
     * @param dateTimeFormatter 格式 yyyy-MM-dd HH:mm:ss
     * @return
     */
    private static boolean canParseByDateTimeFormatter(String source, DateTimeFormatter dateTimeFormatter) {
        try {
            dateTimeFormatter.parse(source);
        } catch (DateTimeParseException e) {
            return false;
        }
        return true;
    }
}

测试一下:
在上面配置的基础上添加部分测试使用的代码

用于前后端交互的bean对象:

@Data
public class UserRO {
    private LocalDateTime createTime1;
    private LocalDateTime createTime2;
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime3;
}

controller层接口:

   @ApiOperation("时间测试")
    @PostMapping("/time")
    public UserRO show(@RequestBody UserRO userRO){
        System.out.println("\n接收到的入参:");
        System.out.println(userRO.getCreateTime1());
        System.out.println(userRO.getCreateTime2());
        System.out.println(userRO.getCreateTime3());
        System.out.println("\n出参:");
        LocalDateTime newTime = LocalDateTime.now();
        UserRO user = new UserRO();
        user.setCreateTime1(newTime);
        user.setCreateTime2(newTime);
        user.setCreateTime3(new Date());
        System.out.println(user.getCreateTime1());
        System.out.println(user.getCreateTime2());
        System.out.println(user.getCreateTime3());
        System.out.println("\n");
        return user;
    }

通过配置类,可以配置后端接口给调用方返的时间格式【字符串、时间戳】、接口调用方传的入参可以是字符串也可以的时间戳,后端会自动解析。

到此这篇关于Java controller接口出入参时间序列化转换操作方法(两种)的文章就介绍到这了,更多相关Java controller接口出入参内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Java实现更改Word中的页面大小和页面方向

    利用Java实现更改Word中的页面大小和页面方向

    这篇文章主要为大家详细介绍了一种高效便捷的方法——通过Java应用程序,以编程方式更改Word中的页面大小和页面方向,感兴趣的可以了解一下
    2023-03-03
  • 使用IDEA直接连接MySQL数据库的方法

    使用IDEA直接连接MySQL数据库的方法

    这篇文章主要介绍了如何使用IDEA直接连接MySQL数据库,首先需要新建一个空项目,第一次连接 需要先下载驱动,文中给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-04-04
  • SWT(JFace)体验之Icon任我变

    SWT(JFace)体验之Icon任我变

    SWT(JFace)体验之Icon任我变
    2009-06-06
  • logback-spring.xml的内容格式详解

    logback-spring.xml的内容格式详解

    这篇文章主要介绍了logback-spring.xml的内容格式详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的的朋友参考下吧
    2023-11-11
  • Java日期格式化的实现(@JsonFormat和@JSONField)

    Java日期格式化的实现(@JsonFormat和@JSONField)

    本文主要介绍了Java日期格式化的实现,主要介绍了@JsonFormat和@JSONField两种方式,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • Java判断用户名和密码是否符合要求过程详解

    Java判断用户名和密码是否符合要求过程详解

    这篇文章主要介绍了Java判断用户名和密码过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • SpringBoot启动及自动装配原理过程详解

    SpringBoot启动及自动装配原理过程详解

    这篇文章主要介绍了SpringBoot启动及自动装配原理过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java ConcurrentHashMap用法案例详解

    Java ConcurrentHashMap用法案例详解

    这篇文章主要介绍了Java ConcurrentHashMap用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java线程生命周期及转换过程

    Java线程生命周期及转换过程

    这篇文章主要介绍了Java线程生命周期及转换过程,线程的生命周期指的是线程从创建到销毁的整个过程初始状态、可运行状态、运行状态、休眠状态、终止状态,更多详细介绍,需要的小伙伴可以参考下面文章内容
    2022-05-05
  • Maven项目如何查找jar包是由哪个依赖引入的

    Maven项目如何查找jar包是由哪个依赖引入的

    这篇文章主要介绍了Maven项目如何查找jar包是由哪个依赖引入的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08

最新评论