【问题标题】:Store Date/Time in UTC, showing Local Time and format in different TimeZones以 UTC 存储日期/时间,以不同时区显示本地时间和格式
【发布时间】:2018-05-08 00:12:46
【问题描述】:

我正在开发一个spring-boot WebApp 项目,其客户位于不同的时区,最终位于不同的国家。我将日期/时间以 UTC 格式存储在数据库中。我还将spring-mvcspring-data-jpahibernateJava time API(Java 8)一起使用。要求之一是向用户显示本地日期时间并根据他们的区域设置(来自用户配置文件)进行格式设置。

我的问题是,什么是让它尽可能透明的最佳位置,以避免因日期/时间转换而污染无处不在的代码。我想到的第一件事是使用过滤器来拦截请求/响应并进行转换,从与当前用户关联的 ThreadLocal 对象中获取位置,但在这一点上,数据仍然过于原始。另一种选择是使用带有休眠功能的拦截器,并在保存之前和读取之后进行转换。

我很感激任何建议,如果可能的话,指定解决方案的最终优点和缺点。

【问题讨论】:

    标签: hibernate spring-mvc time java-8 spring-data-jpa


    【解决方案1】:

    使用拦截器或过滤器对我来说听起来太过分了。当您只想将某些日期时间字段转换为用户特定的时区时,检查每个可以转换为用户时区的日期时间字段的请求太多了。

    更简单的方法是在向/从客户端反序列化您的 java 对象时指定自定义 JsonSerializerJsonDeserializer。由于您使用的是 Java 8,因此您可以使用 ZonedDateTime 将 DateTime 和 Zone 一起存储在一个字段中。

    在会话中存储 userTimeZone 是一种常见的做法。自定义序列化程序需要是 spring bean,以便您可以注入会话,然后获取保存在其中的 userTimeZone。

    分享一些伪代码

    DTO:

    public class TheDTO {
    
        @JsonSerialize(using = UserTimeZoneAwareSerializer.class)
        @JsonDeserialize(using = UserTimeZoneAwareDeserializer.class)
        private ZonedDateTime dateTime;
    
        public ZonedDateTime getDateTime() {
            return dateTime;
        }
    
        public void setDateTime(ZonedDateTime dateTime) {
            this.dateTime = dateTime;
        }
    }
    

    序列化程序,从您的处理程序到客户端:

    @Component
    public class UserTimeZoneAwareSerializer extends JsonSerializer<ZonedDateTime> {
    
        @Autowired
        private HttpSession httpSession;
    
        @Override
        public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
            // Grab the userTimeZone from the session then convert from UTC to userTimeZone
            gen.writeObject(/**/);
        }
    }
    

    反序列化器,从客户端到您的处理程序:

    @Component
    public class UserTimeZoneAwareDeserializer extends JsonDeserializer<ZonedDateTime> {
    
        @Autowired
        private HttpSession httpSession;
    
        @Override
        public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt) 
           // Grab the userTimeZone then convert from userTimeZone to UTC
           // ...
        }
    }
    

    通过这种方式,您可以轻松地注释您想要了解用户时区的ZonedDateTime 字段。

    【讨论】:

    • @Bnrdo,并发怎么样?我猜序列化器/反序列化器将是单例,对吗?如果它们是单例,则无法保证您将为每个客户端注入正确的 httpSession。我认为 ThreadLocal 方法在这种情况下效果更好。是否有机会在不需要添加 DTO 注释的情况下默认定义序列化器/反序列化器?
    • 是的,反序列化器是单通的,httpsession 是会话范围。在这种情况下,您无需担心为用户获取正确的会话。弹簧处理。 Spring 智能地代理 httpsession 的注入,并在内部将其委托给正确的用户。请参阅thisdzone 的好文章
    • 有意义,接受:-)
    猜你喜欢
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-15
    相关资源
    最近更新 更多