timezone-in-spring-mybatis-mysql

spring,mybatis 和 mysql 里的时区问题

大概路径

客户端发起请求

  1. 前端请求
  2. spring 服务端
  3. mybatis 访问
  4. mysql 数据
  5. spring 服务端
  6. 前端显示

mysql

通过命令 show variables like “%time_zone%”; 可以获取 mysql 的时区。

1
2
3
4
5
6
7
8
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| test |
+--------------------+
2 rows in set (0.00 sec)

mybatis

在 spring.datasource.url 参数中需要制定 serverTimezone 和数据库应该对应起来。

1
serverTimezone=GMT%2b8

spring

可以通过如下代码获取时区

1
TimeZone.getDefault()

如果数据为 Date 类型我们可以在服务打印对应的数据来查看数据是否是对的(当然需要考虑时区)。

在对外显示时,我们需要 spring.jackson.time-zone 参数。比如我们如下制定东八区的话就可以看到Date类型被显示成 2019-09-23T00:32:12.000+0800。

1
spring.jackson.time-zone=GMT+8

序列化和反序列化

###反序列化

如果在 query ( 前端传给服务端 )中,默认格式是奇葩的 yyyy-MM-dd’T’HH:mm:ss.SSSZ 格式。一般情况我们会使用到 yyyy-MM-dd HH:mm:ss ,这时候我们需要自定义反序列化。

1
2
@JsonDeserialize(using = CustomJsonDateDeserializer.class)
private Date operateStartDate;

反序列化类

1
2
3
4
5
6
7
8
9
10
11
12
public class CustomJsonDateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = jp.getText();
try {
return format.parse(date);
} catch (ParseException e1) {
throw new RuntimeException(e1);
}
}
}

序列化

如果在 dto (服务器端传给前端)中,默认的格式是奇葩的 2019-09-22T16:32:28.000+0800。一般情况下我们会使用到 yyyy-MM-dd HH:mm:ss ,这时候我们需要自定义序列化。

1
2
@JsonSerialize(using = CustomJsonDateSerializer.class)
private Date create_time;

序列化类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CustomJsonDateSerializer extends JsonSerializer<Date> {

@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
String dateString = dateFormat.format(date);
jsonGenerator.writeString(dateString);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

多时区

如果是多时区,应该使用 UTC 进行存储,然后在显示的地方(前端)转换到各种地方对应的时区。