SpringBoot-JsonFormat与DateTimeFormat注解的使用

x33g5p2x  于2021-09-23 转载在 Spring  
字(5.2k)|赞(0)|评价(0)|浏览(1204)

背景:从数据库获取时间传到前端进行展示的时候,我们有时候可能无法得到一个满意的时间格式的时间日期,在数据库中显示的是正确的时间格式,获取出来却变成了很丑的时间戳,@JsonFormat注解很好的解决了这个问题,我们通过使用@JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题,其次,另一个问题是,我们在使用WEB服务的时,可能会需要用到,传入时间给后台,比如注册新用户需要填入出生日期等,这个时候前台传递给后台的时间格式同样是不一致的,而我们的与之对应的便有了另一个注解,@DataTimeFormat便很好的解决了这个问题,接下来记录一下具体的@JsonFormat与DateTimeFormat的使用过程。

声明:关于@JsonFormat的使用,一定要导入正确完整的包。

小技巧 数据库设计的时候时间字段不要使用时间格 比如: date 或者datetime 而是使用 varchar(30)

因为使用时间类型的话会导致如果前端传递为空,那么插入数据库数据时候会报错

INSERT INTO `t_course` ( `student_id`, `course_name`, `price`, `time`) VALUES ( 1, 'demoData', 1.00, '');

比如上面这条sql语句最后会报错

INSERT INTO `t_course` ( `student_id`, `course_name`, `price`, `time`) VALUES ( 1, 'demoData', 1.00, '')
> 1292 - Incorrect datetime value: '' for column 'time' at row 1
> 时间: 0.002s

意思是时间字段不能插入空值 ,如果你把datetime 改为varchar(30)你在插入就可以了

注意: 因为我们把时间类型的字段改为字符串类型的字段这样会导致,插入和取出都不能保证是时间字符串,那么如果解决这个问题呢?

解决办法: 使用@JsonFormat和@DateTimeFormat这两个注解就行了

注解@JsonFormat

1.使用maven引入@JsonFormat所需要的jar包,我贴一下我这里的pom文件的依赖

<!--JsonFormat-->
 
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.8</version>
        </dependency>
 
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.8</version>
        </dependency>
 
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
  1. 在你需要查询出来的时间的数据库字段对应的实体类的属性上添加@JsonFormat
//设置时区为上海时区,时间格式自己据需求定。
    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    private Date testTime;

这里解释一下:@JsonFormat(pattern=“yyyy-MM-dd”,timezone = “GMT+8”)

pattern:是你需要转换的时间日期的格式

timezone:是时间设置为东八区,避免时间在转换中有误差

提示:@JsonFormat注解可以在属性的上方,同样可以在属性对应的get方法上,两种方式没有区别

完成上面两步之后,我们用对应的实体类来接收数据库查询出来的结果时就完成了时间格式的转换,再返回给前端时就是一个符合我们设置的时间格式了
注意: 如果在代码内部通过getxx进行获取时候还是Date格式,这个需要注意

注解@DateTimeFormat

@DateTimeFormat的使用和@jsonFormat差不多,首先需要引入是引用下面依赖

<!-- joda-time -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.3</version>
        </dependency>

在controller层我们使用spring mvc 表单自动封装映射对象时,我们在对应的接收前台数据的对象的属性上加//@DateTimeFormat//

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date symstarttime;
 
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date symendtime;

我这里就只贴这两个属性了,这里我两个注解都同时使用了,因为我既需要取数据到前台,也需要前台数据传到后台,都需要进行时间格式的转换,可以同时使用

注意事项 :

如果你格式为 “yyyy-MM-dd HH:mm:ss” 那么你传入的字符串也必须是 0000-00-00 00:00:00
1.
如果你传入的格式为 “yyyy/MM/dd HH:mm:ss” 那么你传入的字符串也必须是 0000/00/00 00:00:00
1.
如果你传入的格式为 “yyyy-MM-dd” 那么你传入的字符串是 0000-00-00 00:00:00 最后结果是0000/00/00

总结:

注解 @JsonFormat主要是后台到前台的时间格式的转换

注解 @DateTimeFormat 主要是前后到后台的时间格式的转换

还有特别重要的地方就是 如果前端传递的是空,那么 @DateTimeFormat就会报错,如果数据库里是空那么@JsonFormat就会报错, 这也是弊端,平时注意下就行

如果是Springboot 那么只需要引用下面一个jar包就能使用上面2个注解

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

使用建议

一般如果是前端传递时间数据的话 那么 数据库字段类型设置为varchar(50) 实体类也使用 String 不要加任何转换注解 , 因为这样就避免了很多报错因素,

比如:如果前端时间类型不是必选项时候,传递到后端是空字符串那么,如果我们使用Date接收或者数据库字段是datetime 都会引发错误,具体什么错误下面都有演示
1.
如果是后的自动生成的时间数据的话,那么数据库字段设置为varchar(50) 或者 datetime

这里注意: 如果字段设置为 datetime 那么 JDBC连接串必须附加&zeroDateTimeBehavior=convertToNull 不然为NULL时候会报错

所以建议也设置为varchar(50) 实体类使用Date类型 然后添加 @JsonFormat 和 @DateTimeFormat 注解

出现的问题

问题1

java.sql.SQLException: Value ‘0000-00-00 00:00:00’ can not be represented as java.sql.Timestamp

查询资料后记录下出错原因:
查询的结果集中某数据行的日期值为0000-00-00 00:00:00。

因MySQL的时间类型datetime范围是1000-01-01 00:00:00 到 9999-12-31 23:59:59,所以报错。

如何解决

可以考虑通过修改连接串,附加zeroDateTimeBehavior=convertToNull属性的方式予以规避,例如:

  • jdbc:mysql://localhost:3306/mydbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
    在JDBC连接串中有一项属性:zeroDateTimeBehavior,可以用来配置出现这种情况时的处理策略,该属性有下列三个属性值:

  • exception:默认值,即抛出SQL state [S1009]. Cannot convert value…的异常;

  • convertToNull:将日期转换成NULL值;

  • round:替换成最近的日期即0001-01-01;

从另一个层面讲,这类异常的触发也与timestamp赋值的操作有关,如果能够在设计阶段和记录写入阶段做好逻辑判断,避免写入 '0000-00-00 00:00:00’这类值,那么也可以避免出现 Cannot convert value ‘0000-00-00 00:00:00’ from column N to TIMESTAMP的错误。

问题2

“JSON parse error: Cannot deserialize value of type java.util.Date from String “2021/6/19 12:50:00”: expected format “yyyy-MM-dd HH:mm:ss”; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.util.Date from String “2021/6/19 12:50:00”: expected format “yyyy-MM-dd HH:mm:ss”\n at [Source: (PushbackInputStream); line: 6, column: 11] (through reference chain: com.test.pojo.User[“time”])”

这是因为你前端传入的是2021/6/19 12:50:00格式的字符串 而我们实体类解析时候需要的格式是yyyy-MM-dd HH:mm:ss 如果你非要传递2021/6/19 12:50格式 那么你可以把 格式化改为

@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss",timezone="GMT+8")

问题3

value can not be represented as java.sql.Timestampe;

这个问题是因为数据库中存储的是“ ”空值而不是null 而我们实体类变量是Date类型 空字符串不能赋值给Date

解决办法1

将空字符串的列改为NULL 在Navicat 中点击需要赋值为NULL的那一列右键设置为NULL

如果只想给某一个单元格赋值为NULL那么鼠标点需要赋值的单元格然后在点击表空白处,之后之前被点击的单元格会高亮,

然后在表空白的地方右键,选择设置为NULL

解决办法2:

和前端协调,让前端要不不传,要不就传,传的时候不能给空字符串
1.
后端自己判断如果前端传递的是空字符串那么,我们手动将空“ ”改为NULL

解决办法3

  1. 如果是后端自动生成日期的话那么 在Date类型 上添加@DateTimeFormat 和@JsonFormat

相关文章