一、业务场景

前景提示:当我使用Date类型,并且未作任何处理,返回了一个时间戳给前端,但是前端显示的结果和我后端计算的结果不一致。发现是前端服务器的时区和后端的时区不一致,导致时间戳转换为时间字符串的时候结果不一致。
业务需求:所以不能直接返回时间戳给前端,我就使用 @JsonFormat 进行转换,将时间戳转换为字符串返回给前端。
发现问题:当我使用 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 进行转换的时候,发现最后的结果比当前时间少了8个小时。但是我使用 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 输出又是对的。

二、处理方案

1. 设置注解参数:timezone

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
这里的 GMT+8 就是中国时区

2. 全局设置:objectMapper Config

业务需求:不可能每一个字段都来设置一下这个时区,比较麻烦。需要一个方便的方法。

方法:直接在ObjecctMapper的配置类中进行修改,对ObjectMapper添加时区信息(ObjectMapper 默认是0时区)。使用 objectMapper.setTimeZone(TimeZone.getDefault()).

    @Bean
    public ObjectMapper objectMapper() {
     // xxxxx
     // xxxx
		return new ObjectMapper()
			// xxxx
			// xxxx
			.setTimeZone(TimeZone.getDefault());
	}

备注:
TimeZone.getDefault() 是获取当前服务器的时区。
TimeZone.getTimeZone("Asia/Shanghai") 获取中国的时区。

三、处理过程

  1. JsonFormat 注解会看你输入了时区参数(timezone)没,有的话就用输入的,没有的话就用SerializerProvider
com.fasterxml.jackson.databind.ser.std.DateTimeSerializerBase#createContextual
            } else if (format.hasPattern()) {
                Locale loc = format.hasLocale() ? format.getLocale() : serializers.getLocale();
                SimpleDateFormat df = new SimpleDateFormat(format.getPattern(), loc);
                TimeZone tz = format.hasTimeZone() ? format.getTimeZone() : serializers.getTimeZone();
                df.setTimeZone(tz);
                return this.withFormat(Boolean.FALSE, df);
            } else {
  1. SerializerProvider 的时区如果不进行手动设置的话,就是用的默认时区(0时区)
com.fasterxml.jackson.databind.cfg.BaseSettings
    private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getTimeZone("UTC");
    protected final TimeZone _timeZone;

    public TimeZone getTimeZone() {
        TimeZone tz = this._timeZone;
        return tz == null ? DEFAULT_TIMEZONE : tz;
    }
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐