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{ @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 { @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接口出入参内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
推荐阅读
-
IDEA中使用Gradle构建项目中文报GBK错误的解决方案
-
将Java应用做成exe可执行软件的流程步骤
-
SpringBoot实现多种来源的Zip多层目录打包下载
需要将一批文件(可能分布在不同目录、不同来源)打包成zip格式,按目录结构导出给用户下载。1.核心思路支持将本地服务器上的文...
-
Java中减少if-else的设计模式和优化技巧
前言“过于依赖if-else不仅会让代码变得臃肿不堪,还会使维护成本大大增加。其实,if-else虽然是最基础的条件分支,...
-
Spring Boot 中使用 Drools 规则引擎的完整步骤
-
Spring Boot整合Drools规则引擎实战指南及最佳实践
一、drools简介与核心概念1.1什么是drools?drools是redhat旗下的开源业务规则管理系统(brms),...
-
Springboot项目瘦身之如何将jar包与lib依赖分开打包
将jar包与lib依赖分开打包方法一:项目和依赖完全分离maven-jar-plugin负责生成jar文件(jar文件中...
-
Spring动态修改bean属性配置key的几种方法
静态配置的局限性先来看一个典型场景。假设我们有一个数据源配置类:@configuration@configurationpr...
-
Java如何判断一个IP是否在给定的网段内
-
从零开始学java之二叉树和哈希表实现代码