报错信息

msg: “服务端异常,请联系管理员
JSON parse error: Cannot deserialize value of type java.util.Date from String “2023-11-13 13:13:35”: not a valid representation (error: Failed to parse Date value ‘2023-11-13 13:13:35’: Cannot parse date “2023-11-13 13:13:35”: while it seems to fit format ‘yyyy-MM-dd’T’HH:mm:ss.SSSX’, parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.util.Date from String “2023-11-13 13:13:35”: not a valid representation (error: Failed to parse Date value ‘2023-11-13 13:13:35’: Cannot parse date “2023-11-13 13:13:35”: while it seems to fit format ‘yyyy-MM-dd’T’HH:mm:ss.SSSX’, parsing fails (leniency? null))↵ at [Source: (PushbackInputStream); line: 1, column: 233] (through reference chain: com.java1234.entity.Product[“hotDateTime”])”

配置文件配置application.yml:

 
spring: 
    jackson:
        #字符串时间,用这行表示
        date-format: yyyy-MM-dd 
        #设置为东八区时间
        timezone: GMT+8
       
spring:
  # 配置日期格式化
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss  #时间戳统一转换为指定格式
    time-zone: GMT+8  # 时区修改为东8区

application.properties配置方式

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss	#时间戳统一转换为指定格式
spring.jackson.time-zone=GMT+8	# 时区修改为东8区

【注意】这里需要修改时区time-zone:数据库默认时区是格林尼治的时间,如果不设置,会比实际时间少8个小时(北京时间)。

项目场景:

前端画面上有一个可以选择年月的日期选择器,代码如下:


      <el-form-item label="统计月份" prop="billsDate" v-if="isShowMonth">
        <el-date-picker clearable size="small"
                        v-model="queryParams.billsDate"
                        type="month"
                        value-format="yyyy-MM"
                        placeholder="请选择统计月份"
                        :disabled="inputDisable">
        </el-date-picker>
      </el-form-item>

选择的数据使用post请求将数据传递给后端

问题描述

后端接收的时候报如下错误

JSON parse error: Cannot deserialize value of type java.util.Date from String “2022-01”:

后端接收的实体类如下

    /**
     * 客户ID
     */
    private Long companyId;
 
    /**
     * 客户code
     */
    private String companyCode;
 
    /**
     * 账单统计类型
     */
    private Integer billStatisticsType;
 
    /**
     * 账单时间
     */
    private Date billsDate;
   

原因分析:

因为传入的参数是 String 类型的,而用来接收参数的项目的属性是 java.util.Date 类型的,类型无法转换。

springboot默认采用jackson,而jackson只能识别以下几种日期格式

“yyyy-MM-dd’T’HH:mm:ss.SSSZ”; “yyyy-MM-dd’T’HH:mm:ss.SSS’Z’”; “yyyy-MM-dd”; “EEE, dd MMM yyyy HH:mm:ss zzz”; long类型的时间戳(毫秒时间戳)

解决方案:

所以在接收到数据的时候,需要通过jackson把数据转化。jackson转化默认的时间格式 'yyyy-MM-dd’T’HH:mm:ss.SSS’,所以就会出现异常,所以要设置时区的格式为"yyyy-MM"。

添加@JsonFormat注解,来说明接收格式

代码如下

    /**
     * 客户ID
     */
    private Long companyId;
 
    /**
     * 客户code
     */
    private String companyCode;
 
    /**
     * 账单统计类型
     */
    private Integer billStatisticsType;
 
    /**
     * 账单时间
     */
    @JsonFormat(pattern = "yyyy-MM")
    private Date billsDate;

SpringBoot中日期时间类型的序列化与反序列化

目录

1、背景

2、序列化时间戳

3、反序列化时间戳

4、使用示例

1、背景

序列化是将一个对象转换成字节序列的过程,可以将这些字节序列存储在磁盘或通过网络传输。反序列化是将字节序列转换回对象的过程。

2、序列化时间戳

将Instant类型转换为前端需要的长整型Long,可以通过继承JsonSerializer类,实现serialize方法即可。



package com.fandou.component.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.time.Instant;

/**
 * Instant序列化为Long类型
 */
public class InstantToLongSerializer extends JsonSerializer<Instant> {
    @Override
    public void serialize(Instant value, JsonGenerator generator, SerializerProvider serializers) throws IOException {
        // 通过JSON生成器,将要序列化的Instant类型对象即value的时间戳值写入为数值,即前端需要的长整型
        generator.writeNumber(value.toEpochMilli());
    }
}

3、反序列化时间戳

	同样,将长整型Long转换为Instant类型,可以通过继承JsonDeserializer类,实现deserialize方法即可。

package com.fandou.component.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Instant;

/**
 * Long反序列化为Instant类型
 *
 */
public class LongToInstantDeserializer extends JsonDeserializer<Instant> {
    @Override
    public Instant deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        // 从JSON初始化器中读取对应的长整型时间错值,使用Instant的ofEpochMilli初始化为Instant类型返回
        return Instant.ofEpochMilli(jsonParser.getValueAsLong());
    }
}

4、使用示例

使用@JsonSerialize注解或@JsonDeserialize注解标记需要序列化或反序列化的对象属性上,注解中的using属性值指定为步骤2或步骤3的序列化类或反序列化类型即可。在运行的过程中,SpringBoot
框架会自动完成日期时间的序列化和反序列化。



package com.example.demo.vo;

import com.fandou.component.json.InstantToLongSerializer;
import com.fandou.component.json.LongToInstantDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import lombok.Getter;
import lombok.Setter;

import java.time.Instant;

/**
 * 用户VO对象
 *
 * 
 */
@Setter
@Getter
public class User {
    /**
     * 主键id
     */
    private Long id;

    /**
     * 用户账号
     */
    private String userAccount;

    /**
     * 用户昵称
     */
    private String nickname;

    /**
     * 创建时间:使用@JsonSerialize注解和@JsonDeserialize注解实现创建时间属性的序列化和反序列化
     */
    @JsonSerialize(using = InstantToLongSerializer.class)
    @JsonDeserialize(using = LongToInstantDeserializer.class)
    private Instant createTime;
}

02-12 12:40