SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
當(dāng)我們使用SpringBoot+Mysql開(kāi)發(fā)系統(tǒng)時(shí),總是統(tǒng)一設(shè)置UTC+8時(shí)區(qū),這樣用戶在任何地區(qū)訪問(wèn)系統(tǒng),展示的時(shí)間都是國(guó)內(nèi)標(biāo)準(zhǔn)時(shí)間,體驗(yàn)不友好,下面通過(guò)獲取當(dāng)前用戶系統(tǒng)所在的時(shí)區(qū),給用戶展示不同的時(shí)間。
一、用戶時(shí)區(qū)的獲取
我們可以通過(guò)JavaScript來(lái)獲取系統(tǒng)所在的時(shí)區(qū),然后統(tǒng)一設(shè)置在請(qǐng)求頭里。
Intl.DateTimeFormat().resolvedOptions().timeZone; // Asia/Shanghai
二、核心代碼
這里統(tǒng)一使用LocalDateTime,更方便的處理時(shí)區(qū)轉(zhuǎn)換問(wèn)題,通過(guò)標(biāo)識(shí)當(dāng)前LocalDateTime對(duì)象所屬時(shí)區(qū),然后轉(zhuǎn)換為目標(biāo)時(shí)區(qū)時(shí)間。
public LocalDateTime convertLocalDateTime(LocalDateTime localDateTime, ZoneId originZoneId,
ZoneId targetZoneId)
{
return localDateTime.atZone(originZoneId).withZoneSameInstant(targetZoneId).toLocalDateTime();
}
三、SpringBoot返回json時(shí)統(tǒng)一處理時(shí)區(qū)
當(dāng)程序從數(shù)據(jù)庫(kù)中讀取出并轉(zhuǎn)換成LocalDateTime對(duì)象,并經(jīng)過(guò)業(yè)務(wù)邏輯處理,這時(shí)候該對(duì)象還是屬于UTC+8時(shí)區(qū),對(duì)應(yīng)的ZoneId=Asia/Shanghai,當(dāng)需要返回給前端時(shí),可以通過(guò)自定義jackson序列化器,在LocalDateTime轉(zhuǎn)json前轉(zhuǎn)換到用戶目標(biāo)時(shí)區(qū)。
@Configuration
public class JacksonConfiguration
{
@Autowired
private JacksonProperties jacksonProperties; /**
* 時(shí)區(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è)定用戶時(shí)區(qū)ZoneId=Africa/Sao_Tome,并且自定義處理了LocalDateTime反序列化器,當(dāng)使用ResquestBody注解時(shí),對(duì)象中的LocalDateTime屬性值也會(huì)轉(zhuǎn)換成UTC+8時(shí)區(qū),不用再額外處理,可直接保存到數(shù)據(jù)庫(kù)。
四、SpringBoot接收時(shí)間參數(shù)統(tǒng)一處理時(shí)區(qū)
除了上面所說(shuō)通過(guò)ResquestBody注解來(lái)接收參數(shù)外,還可能通過(guò)Get或者Post參數(shù)來(lái)接收LocalDateTime對(duì)象,這時(shí)候我們就要自定義一個(gè)Converter來(lái)處理String轉(zhuǎn)換到LocalDateTime,同時(shí)把用戶提交的屬于用戶時(shí)區(qū)的對(duì)象轉(zhuǎn)換成UTC+8時(shí)區(qū)對(duì)象。
@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é)
通過(guò)上面的處理,JavaScript負(fù)責(zé)獲取用戶時(shí)區(qū),并且每次請(qǐng)求時(shí)帶到后臺(tái),后臺(tái)在接收請(qǐng)求和返回前端時(shí)統(tǒng)一轉(zhuǎn)換用戶時(shí)區(qū),業(yè)務(wù)處理時(shí)不必再考慮時(shí)區(qū)問(wèn)題。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 深入詳解SpringBoot中時(shí)區(qū)問(wèn)題解決與配置方案
- SpringBoot時(shí)區(qū)問(wèn)題解決以及徹底解決時(shí)差問(wèn)題
- springboot項(xiàng)目如何設(shè)置時(shí)區(qū)
- 如何解決springboot數(shù)據(jù)庫(kù)查詢時(shí)出現(xiàn)的時(shí)區(qū)差異問(wèn)題
- springboot如何統(tǒng)一設(shè)置時(shí)區(qū)
- SpringBoot中?Jackson?日期的時(shí)區(qū)和日期格式問(wèn)題解決
- SpringBoot:JPA + AuditingEntityListener時(shí)區(qū)設(shè)置方式
- 關(guān)于SpringBoot mysql數(shù)據(jù)庫(kù)時(shí)區(qū)問(wèn)題
- SpringBoot時(shí)區(qū)設(shè)置的幾個(gè)方面小結(jié)
相關(guān)文章
java微信掃碼支付模式一線下支付功能實(shí)現(xiàn)
本篇文章主要介紹了JAVA微信掃碼支付模式一線下支付功能實(shí)現(xiàn),具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11
JAVA設(shè)計(jì)模式零基礎(chǔ)解析之單例模式的八種方式
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類(lèi)編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性2021-10-10
利用Java工具類(lèi)Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能
這篇文章主要介紹了利用Java工具類(lèi)Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能,利用Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn),校驗(yàn)的Servlet與今天的第一篇是一樣的,唯一就是驗(yàn)證碼的生成是不一樣的,利用Hutool生成驗(yàn)證碼更快捷.需要的朋友可以參考下2022-10-10
Java操作excel的三種常見(jiàn)方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java操作excel的三種常見(jiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Spring通過(guò)<import>標(biāo)簽導(dǎo)入外部配置文件
之前文章里我們講到Spring加載Xml配置文件的細(xì)節(jié),那么加載完了我們肯定要解析這個(gè)配置文件中定義的元素。這篇我們首先來(lái)分析下Spring是如何通過(guò)標(biāo)簽導(dǎo)入外部配置文件的。2021-06-06
Java單機(jī)環(huán)境實(shí)現(xiàn)定時(shí)任務(wù)技術(shù)
這篇文章主要介紹了Java單機(jī)環(huán)境實(shí)現(xiàn)定時(shí)任務(wù)技術(shù),文章內(nèi)容介紹詳細(xì),具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-04-04
SpringMVC攔截器實(shí)現(xiàn)單點(diǎn)登錄
這篇文章主要介紹了SpringMVC攔截器實(shí)現(xiàn)單點(diǎn)登錄,簡(jiǎn)單介紹了springmvc攔截器,單點(diǎn)登錄實(shí)現(xiàn)原理等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

