SpringBoot如何根據(jù)用戶系統(tǒng)時區(qū)動態(tài)展示時間
根據(jù)用戶系統(tǒng)時區(qū)動態(tài)展示時間
當(dāng)我們使用SpringBoot+Mysql開發(fā)系統(tǒng)時,總是統(tǒng)一設(shè)置UTC+8時區(qū),這樣用戶在任何地區(qū)訪問系統(tǒng),展示的時間都是國內(nèi)標(biāo)準(zhǔn)時間,體驗不友好,下面通過獲取當(dāng)前用戶系統(tǒng)所在的時區(qū),給用戶展示不同的時間。
一、用戶時區(qū)的獲取
我們可以通過JavaScript來獲取系統(tǒng)所在的時區(qū),然后統(tǒng)一設(shè)置在請求頭里。
Intl.DateTimeFormat().resolvedOptions().timeZone; // Asia/Shanghai
二、核心代碼
這里統(tǒng)一使用LocalDateTime,更方便的處理時區(qū)轉(zhuǎn)換問題,通過標(biāo)識當(dāng)前LocalDateTime對象所屬時區(qū),然后轉(zhuǎn)換為目標(biāo)時區(qū)時間。
public LocalDateTime convertLocalDateTime(LocalDateTime localDateTime, ZoneId originZoneId,
ZoneId targetZoneId)
{
return localDateTime.atZone(originZoneId).withZoneSameInstant(targetZoneId).toLocalDateTime();
}
三、SpringBoot返回json時統(tǒng)一處理時區(qū)
當(dāng)程序從數(shù)據(jù)庫中讀取出并轉(zhuǎn)換成LocalDateTime對象,并經(jīng)過業(yè)務(wù)邏輯處理,這時候該對象還是屬于UTC+8時區(qū),對應(yīng)的ZoneId=Asia/Shanghai,當(dāng)需要返回給前端時,可以通過自定義jackson序列化器,在LocalDateTime轉(zhuǎn)json前轉(zhuǎn)換到用戶目標(biāo)時區(qū)。
@Configuration
public class JacksonConfiguration
{
@Autowired
private JacksonProperties jacksonProperties; /**
* 時區(qū)轉(zhuǎn)換
*
* @param localDateTime
* @param originZoneId
* @param targetZoneId
* @return
*/
public static LocalDateTime convertLocalDateTime(LocalDateTime localDateTime, ZoneId originZoneId,
ZoneId targetZoneId)
{
return localDateTime.atZone(originZoneId).withZoneSameInstant(targetZoneId).toLocalDateTime();
} /**
* LocalDateTime序列化
*/
public static class CustomLocalDateTimeSerializer extends JsonSerializer<LocalDateTime>
{
private DateTimeFormatter formatter; public CustomLocalDateTimeSerializer(DateTimeFormatter formatter)
{
super();
this.formatter = formatter;
} @Override
public void serialize(LocalDateTime value, JsonGenerator generator, SerializerProvider provider)
throws IOException
{
generator.writeString(convertLocalDateTime(value, ZoneId.of("Asia/Shanghai"), ZoneId.of("Africa/Sao_Tome"))
.format(formatter));
} } /**
* LocalDateTime反序列化
*
*/
public static class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime>
{
private DateTimeFormatter formatter; public CustomLocalDateTimeDeserializer(DateTimeFormatter formatter)
{
super();
this.formatter = formatter;
} @Override
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JacksonException
{
return convertLocalDateTime(LocalDateTime.parse(parser.getText(), formatter), ZoneId.of("Africa/Sao_Tome"),
ZoneId.of("Asia/Shanghai"));
} } @Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer()
{
return builder ->
{
builder.serializerByType(LocalDateTime.class,
new CustomLocalDateTimeSerializer(DateTimeFormatter.ofPattern(jacksonProperties.getDateFormat())));
builder.deserializerByType(LocalDateTime.class,
new CustomLocalDateTimeDeserializer(DateTimeFormatter.ofPattern(jacksonProperties.getDateFormat())));
};
}
}
上面示例代碼設(shè)定用戶時區(qū)ZoneId=Africa/Sao_Tome,并且自定義處理了LocalDateTime反序列化器,當(dāng)使用ResquestBody注解時,對象中的LocalDateTime屬性值也會轉(zhuǎn)換成UTC+8時區(qū),不用再額外處理,可直接保存到數(shù)據(jù)庫。
四、SpringBoot接收時間參數(shù)統(tǒng)一處理時區(qū)
除了上面所說通過ResquestBody注解來接收參數(shù)外,還可能通過Get或者Post參數(shù)來接收LocalDateTime對象,這時候我們就要自定義一個Converter來處理String轉(zhuǎn)換到LocalDateTime,同時把用戶提交的屬于用戶時區(qū)的對象轉(zhuǎn)換成UTC+8時區(qū)對象。
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer
{
@Autowired
private WebMvcProperties webMvcProperties; @Override
public void addFormatters(FormatterRegistry registry)
{
registry.addConverter(new Converter<String, LocalDateTime>()
{ private LocalDateTime convertLocalDateTime(LocalDateTime localDateTime, ZoneId originZoneId,
ZoneId targetZoneId)
{
return localDateTime.atZone(originZoneId).withZoneSameInstant(targetZoneId).toLocalDateTime();
} @Override
public LocalDateTime convert(String source)
{
return convertLocalDateTime(
LocalDateTime.parse(source,
DateTimeFormatter.ofPattern(webMvcProperties.getFormat().getDateTime())),
ZoneId.of("Africa/Sao_Tome"), ZoneId.of("Asia/Shanghai"));
} });
}}
五、總結(jié)
通過上面的處理,JavaScript負(fù)責(zé)獲取用戶時區(qū),并且每次請求時帶到后臺,后臺在接收請求和返回前端時統(tǒng)一轉(zhuǎn)換用戶時區(qū),業(yè)務(wù)處理時不必再考慮時區(qū)問題。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談關(guān)于Java正則和轉(zhuǎn)義中\(zhòng)\和\\\\的理解
這篇文章主要介紹了淺談關(guān)于Java正則和轉(zhuǎn)義中\(zhòng)\和\\\\的理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Java 基于Jakarta Mail實現(xiàn)收發(fā)郵件
這篇文章主要介紹了Java 基于Jakarta Mail實現(xiàn)收發(fā)郵件的功能,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-04-04
SpringBoot集成內(nèi)存數(shù)據(jù)庫H2的實踐
h2是內(nèi)存數(shù)據(jù)庫,查詢高效,可以在開發(fā)初期使用它。本文主要介紹了SpringBoot集成內(nèi)存數(shù)據(jù)庫H2的實踐,具有一定的參考價值,感興趣的可以了解一下2021-09-09
SpringBoot通過自定義注解實現(xiàn)配置類的自動注入的實現(xiàn)
本文主要介紹了SpringBoot通過自定義注解實現(xiàn)配置類的自動注入的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
IntelliJ IDEA中程序包org.slf4j找不到的解決
這篇文章主要介紹了IntelliJ IDEA中程序包org.slf4j找不到的解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Java實戰(zhàn)之基于swing的QQ郵件收發(fā)功能實現(xiàn)
這篇文章主要介紹了Java實戰(zhàn)之基于swing的QQ郵件收發(fā)功能實現(xiàn),文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04

