SpringCloud Feign 传输Date类型参数的时差问

2019-02-19  本文已影响7人  OldChicken_

SpringCloud是搭建微服务的常用工具,Feign是微服务之间的通信的工具,在用Feign传递java.util.Date类型的参数时,会有时差问题,在CST(中国)时区运行时,这个时差为14小时。

错误原因——CTS的误解

  1. Feign客户端在进行通信时,会将Date类型对象转为String类型,如果这个时间是北京时间2019年2月19日20点30分,因为中国的时区叫做CTS,所以转化后的String为“Tue Feb 19 20:30:00 CST 2019”.
  2. 服务端将接收的String类型日期转换为Date类型,转换采用的是Date的默认构造器new Date('Tue Feb 19 20:30:00 CST 2019'),这里就是错误发生的时刻,因为CTS代表的时区其实有四个(Central Standard Time (USA) UT-6:00、Central Standard Time (Australia) UT+9:30、China Standard Time UT+8:00、Cuba Standard Time UT-4:00),同时表示美国,澳大利亚,中国,古巴四个国家的标准时间。根据JavaDoc,jvm会将CTS理解成了美国中部时区,因此造成了时区错误。

JVM见到CTS默认是美国的时区(UT-6:00),与中国时区(UT+8:00)相差14个小时。

解决办法

在客户端添加代码,规定Feign在将Date参数转化成String参数的格式:

import org.springframework.cloud.netflix.feign.FeignFormatterRegistrar;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class DateFormatRegister implements FeignFormatterRegistrar {

    public DateFormatRegister() {
    }

    @Override
    public void registerFormatters(FormatterRegistry registry) {
        registry.addConverter(Date.class, String.class, new Date2StringConverter());
    }

    private class Date2StringConverter implements Converter<Date, String> {
        @Override
        public String convert(Date source) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(source);
        }
    }
}

在服务端添加代码,规定SpringContext在String和Date时的用的转化器,让转化器知道我们在客户端配置的参数格式:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import javax.annotation.PostConstruct;
import java.util.Date;

@Configuration
public class WebConfigBeans {

    @Autowired
    private RequestMappingHandlerAdapter handlerAdapter;

    @PostConstruct
    public void initEditableValidation() {
        ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter
                .getWebBindingInitializer();
        if (initializer.getConversionService() != null) {
            GenericConversionService genericConversionService = (GenericConversionService) initializer
                    .getConversionService();
            genericConversionService.addConverter(String.class, Date.class, new String2DateConverter());
        }
    }
}
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

class String2DateConverter implements Converter<String, Date> {

    @Override
    public Date convert(String source) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            return simpleDateFormat.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

PS.由于这个问题在中国比较常见,所以这次百度到的方法要比Google更好一些 :)

参考文献
SpringCloud Feign 传参问题及传输Date类型参数的时差
Java Date数据类型时差问题

上一篇下一篇

猜你喜欢

热点阅读