SpringMVC日期格式属性自动转成时间戳实现源码分析

背景介绍

SpringMVC搭建的微服务系统,后端数据库对时间类型的存储使用的是Long类型,而前端框架倾向于使用yyyy-MM-dd HH:mm:ss这种标准显示格式,前端JSON格式的请求报文与后台的接口交互都需要进行格式转换,这部分转换功能由后台实现。

使用时我们发现,前端定义的JSON请求,时间格式为yyyy-MM-dd HH:mm:ss,如果后台定义的POJO相应的属性为Long类型,可以自动转换为时间戳,对此非常好奇,框架是如何实现这一功能的?

框架选型、版本及主要功能
  1. spring boot 2.1.6.RELEASE
  2. spring cloud Greenwich.SR3
  3. alibaba fastjson 1.2.60

注意json框架使用的是fastjson

代码演示

为了方便演示,定义一个特别简单的POJO类:

public class DateReq {
   

	private String dateFormat;
	private Long timestamp;

    // 省略getter/setter/toString方法
}

再定义一个简单的Controller方法:

@RestController
public class DemoController {
   

	@PostMapping(value = "/json/demo/info")
	public ApiResponse<?> dateJson(@RequestBody DateReq request) {
   
		System.out.println(request);
	}
}

请求报文如下:

{
   
    "dateFormat": "2020-08-07 18:50:00",
    "timestamp": "2020-08-07 18:50:00"
}

响应的结果:DateReq{dateFormat='2020-08-07 18:50:00', timestamp=1596797400000}

从结果可以发现,dateFormat字段我们定义的是String类型,timestamp定义的是Long类型,请求报文两个字段使用相同的值,但是到了Controller方法里,timestamp自动变成Long类型的时间戳了,并且是按东8区转换的。

在这里我们可以得到一个使用经验:POJO的时间格式是可以自动转换成Long类型时间戳的,默认时区取操作系统的时区,或者通过jvm参数-Duser.timezone=GMT+08设置。

源码阅读

既然看到了自动转换的效果,非常好奇框架是怎么实现的,我们通过断点查找堆栈:

deserialze:79, LongCodec (com.alibaba.fastjson.serializer)
parseField:85, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:1224, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:850, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseRest:1538, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:-1, FastjsonASMDeserializer_3_DateReq (com.alibaba.fastjson.parser.deserializer)
deserialze:284, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:692, DefaultJSONParser (com.alibaba.fastjson.parser)
parseObject:383, JSON (com.alibaba.fastjson)
parseObject:448, JSON (com.alibaba.fastjson)
parseObject:556, JSON (com.alibaba.fastjson)
readType:263, FastJsonHttpMessageConverter (com.alibaba.fastjson.support.spring)
read:237, FastJsonHttpMessageConverter (com.alibaba.fastjson.support.spring)
readWithMessageConverters:204, AbstractMessageConverterMethodArgumentResolver (org.springframework.web.servlet.mvc.method.annotation)
readWithMessageConverters:157, RequestResponseBodyMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
resolveArgument:130, RequestResponseBodyMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
resolveArgument:124, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)

发现了两处有价值的信息:

  1. 触发消息类型转换类是FastJsonHttpMessageConverter
  2. 真正完成类型映射是fastjson框架

有这个思路,阅读源码时可以把重点放在fastjson上,从JSON反序列化为POJO,Long类型字段处理,找到这段代码:

public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
   
        JSONLexer lexer = parser.lexer;

        Long longObject;
        try {
   
            int token = lexer.token();
            if (token == 2) {
   
                long longValue =
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值