Quietly tell you

没有什么技术是一篇文档解决不了的,如果有,那就两篇。

解决Spring Boot时间类型输出为Long类型的时间戳问题. 假如你尝试了网上所有的方案都没有解决的话, 不妨试试看这里.

背景

Spring Boot 2版本, 在返回给前端的JSON中Date类型为Long类型的时间戳. 而我需要返回为”yyyy-MM-ddHH:mm:ss”类型的格式化字符串. 项目初期是可以的,  到后期突然成为了long类型, 而配置没有改动. JsonDate格式化相关配置如下:

package com.front.pay.conf;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
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 org.springframework.boot.jackson.JsonComponent;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author: 郭胜凯
 * @Date: 2019-06-11 11:36
 * @Email 719348277@qq.com
 * @Description: 全局Rest full API Date类型JSON 格式化
 */
@JsonComponent
public class DateFormatConfig {

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 日期格式化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(dateFormat.format(date));
        }
    }

    /**
     * 解析日期字符串
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                throws IOException, JsonProcessingException {
            try {
                return dateFormat.parse(jsonParser.getText());
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

后期该配置失效后, 尝试过以下方案, 无解:

配置yml, 禁用时间戳转换(这是在spring boot 1 版本的东西, 在spring boot 1 版本中, 默认Date类型输出就是时间戳)

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false

分析

  1. 断点调试, Controller方法 return result中开始跟断电, 一直到最后, 发现spring并没有使用`DateFormatConfig`这个类.
  2. 因此, 怀疑`DateFormatConfig`并没有被Spring扫描到, 在其中添加inti方法和@PostConstruct注解并输出日志, 发现日志正常输出. 因此排除这个可能.
  3. 怀疑Spring随扫描到了, 但未注册到HttpMessageConverter, 在`HttpMessageConvertersAutoConfiguration中打断点, 发现配置被`WebMvcConfigurationSupport`覆盖了.

WebMvcConfigurationSupport这个类是我的拦截器继承的类, 拦截远程访问时的header集成相关和跨域相关配置.

 

解决方案

在Spring boot 2 中, 官方推荐这种方式添加拦截器配置实现 class MyConfigurerAdapter extends WebMvcConfigurationSupport {}

但这种配置会导致`JsonSerializer`JsonDeserializer的自定义实现被覆盖, 因此改为 `class MyConfigurerAdapter implements WebMvcConfigurer {}` 方式实现拦截器配置.

验证

问题解决: 响应结果如下:

{
    "code": 0,
    "message": "列表获取成功",
    "responseBody": {
        "data": {
            "totalSize": 1,
            "totalPageSize": 1,
            "page": 1,
            "length": 10,
            "list": [
                {
                    "id": 22,
                    "applicationUserId": 19,
                    "storeId": 6,
                    "applicationStoreName": "旭日餐饮2",
                    "applicationStoreNameArea": null,
                    "applicationUserName": "王艳红",
                    "applicationUserPhone": "183***621",
                    "createDate": "2019-07-01 15:52:13",
                    "businessNo": "45121***5633",
                    "idCardNum": "131122***03443",
                    "idCardStartDate": "20140110",
                    "idCardEndDate": "20240110",
                    "bankCardNum": "62170***4443",
                    "idCardPositive": "http://dev-xgjg.oss-cn-beijing.aliyuncs.com/1/156*8.jpg?Expires=1647613200&OSSAccessKeyId=LT***mlTSiQ&Signature=Xzjd30IZu***D448EE%3D",
                    "idCardNegative": "http://dev-xgjg.oss-cn-beijing.aliyuncs.com/1/156*86.jpg?Expires=1647613200&OSSAccessKeyId=LTAIe***SiQ&Signature=HbzgNHJdjz***Gyuig0%3D",
                    "bankCardPositive": "http://dev-xgjg.oss-cn-beijing.aliyuncs.com/1/15*1196.jpg?Expires=1647613200&OSSAccessKeyId=LTAI**TSiQ&Signature=DOOcQb2Am0%2BEMzpq***VXVQ%3D",
                    "status": "PASS",
                    "auditUserId": 1,
                    "auditUserName": "admin",
                    "auditDate": "2019-07-02 15:05:43",
                    "auditMsg": null,
                    "auditInfo": "{\"applicationStoreNameArea\":\"Y\",\"applicationStoreName\":\"Y\",\"applicationUserName\":\"Y\",\"businessNo\":\"Y\",\"applicationUserPhone\":\"Y\",\"idCardNum\":\"Y\",\"bankCardNum\":\"Y\"}",
                    "openBankName": "中国建设银行",
                    "openBankTypeName": "储蓄卡",
                    "businessImg": null,
                    "businessStartDate": null,
                    "businessEndDate": null,
                    "leveDscp": null,
                    "auditInfoEntity": {
                        "applicationStoreNameArea": "Y",
                        "applicationStoreName": "Y",
                        "applicationUserName": "Y",
                        "businessNo": "Y",
                        "applicationUserPhone": "Y",
                        "idCardNum": "Y",
                        "bankCardNum": "Y"
                    },
                    "logs": null
                }
            ]
        }
    },
    "success": true
}

 暴力解决方案

理论上, 我觉得重写Date类的toString()方法也可以实现, 这很暴力, 但未做尝试, 有时间或者以上方案无法解决的话, 可以试试.

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注