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)文章
Java線程中的Thread.yield()詳細(xì)解析
這篇文章主要介紹了Java線程中的Thread.yield()詳細(xì)解析,yield()讓當(dāng)前線程從運行狀態(tài)?轉(zhuǎn)為?就緒狀態(tài),以允許具有相同優(yōu)先級的其他線程獲得運行機(jī)會,需要的朋友可以參考下2023-11-11
MyBatis中如何查詢某個時間段內(nèi)的數(shù)據(jù)
這篇文章主要介紹了MyBatis中如何查詢某個時間段內(nèi)的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
tk.Mybatis 插入數(shù)據(jù)獲取Id問題
本文主要介紹了tk.Mybatis 插入數(shù)據(jù)獲取Id問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
@JsonSerialize(using = LongToStringUtil.class)注解的使
這篇文章主要介紹了@JsonSerialize(using = LongToStringUtil.class)注解的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08
SpringCloud Zuul過濾器和谷歌Gauva實現(xiàn)限流
這篇文章主要介紹了SpringCloud Zuul過濾器和谷歌Gauva實現(xiàn)限流,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03

