SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式
之前接到需求,需要給APP內(nèi)的H5活動(dòng)的接口加上時(shí)效性,防止活動(dòng)后還有用戶(hù)調(diào)用接口;
因?yàn)橛行〩5活動(dòng)是長(zhǎng)期的,有些是短期的,所以我需要做好區(qū)分,因?yàn)槲覀兊腶pp是國(guó)外用戶(hù)在用的,所以還要考慮的時(shí)區(qū)的問(wèn)題;
想了一下決定用注解
+`攔截器
的方式去實(shí)現(xiàn)
默認(rèn)已經(jīng)創(chuàng)建好了SpringBoot項(xiàng)目
一、獲取不同時(shí)區(qū)的時(shí)間方式
1、通過(guò)時(shí)區(qū)獲取所在時(shí)區(qū)時(shí)間
/** * 獲得東八區(qū)時(shí)間 * * @return */ public static String getChinaTime() { TimeZone timeZone = TimeZone.getTimeZone("GMT+8:00"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); simpleDateFormat.setTimeZone(timeZone); return simpleDateFormat.format(new Date()); }
2、通過(guò)地區(qū)獲取所在時(shí)區(qū)時(shí)間
根據(jù)ZoneId
獲取當(dāng)?shù)貢r(shí)間
ZonedDateTime
是結(jié)合了LocalDateTime類(lèi)與 ZoneId 類(lèi)。它用于表示具有時(shí)區(qū)(地區(qū)/城市,如歐洲/巴黎)的完整日期(年,月,日)和時(shí)間(小時(shí),分鐘,秒,納秒)
ZoneId pstZoneId = ZoneId.of("America/Los_Angeles"); DateTimeFormatter pstDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(pstZoneId); ZonedDateTime pstZonedDateTime = ZonedDateTime.parse(time, pstDateTimeFormatter);
3、獲取所在時(shí)區(qū)的時(shí)間戳
String region = "America/Los_Angeles"; ZoneId pstZoneId = ZoneId.of(region); long nowTime = ZonedDateTime.now(pstZoneId).toInstant().toEpochMilli(); //nowTime時(shí)間戳
當(dāng)然還有其他方式獲取得到,網(wǎng)上有很多工具類(lèi)~~~
二、創(chuàng)建地區(qū)/時(shí)區(qū)枚舉類(lèi)
region屬性表示時(shí)間,timeZone表示時(shí)區(qū)
還有一點(diǎn)要注意的,一些國(guó)家有冬令時(shí)和夏令時(shí)的區(qū)分,比如美國(guó)、德國(guó)、法國(guó)等,這里我同一用了協(xié)同世界時(shí)
public enum TimeZoneEnum { ? Asia_Shanghai("Asia/Shanghai","+8:00"),//中國(guó)-上海 Asia_Hong_Kong("Asia/Hong_Kong","+8:00"),//香港 Asia_Macau("Asia/Macau","+8:00"),//澳門(mén) Asia_Taipei("Asia/Taipei","+8:00"),//臺(tái)灣 Asia_Singapore("Asia/Singapore","+8:00"),//新加坡 Asia_Bangkok("Asia/Bangkok","+7:00"),//泰國(guó)-曼谷 Asia_Calcutta("Asia/Calcutta","+5:30"),//印度-加爾各答 Asia_Tokyo("Asia/Tokyo","+9:00"),//日本-東京 Asia_Seoul("Asia/Seoul","+9:00"),//韓國(guó)-首爾 Asia_Karachi("Asia/Karachi","+5:00"),//巴基斯坦 America_Los_Angeles("America/Los_Angeles","-8:00"),//洛杉磯 America_New_York("America/New_York","-5:00"),//紐約 Europe_London("Europe/London","+0:00"),//英國(guó)-倫敦 Europe_Paris("Europe/Paris","+1:00"),//法國(guó)-巴黎 Europe_Berlin("Europe/Berlin","+1:00"),//德國(guó)-柏林 Asia_Jakarta("Asia/Jakarta","+7:00"),//印度尼西亞-雅加達(dá) Asia_Kuala_Lumpur("Asia/Kuala_Lumpur","+8:00");//馬來(lái)西亞-吉隆坡 ? private String region; private String timeZone; ? TimeZoneEnum(String region, String timeZone) { this.region = region; this.timeZone = timeZone; } ? public String getRegion() { return region; } ? public TimeZoneEnum setRegion(String region) { this.region = region; return this; } ? public String getTimeZone() { return timeZone; } ? public TimeZoneEnum setTimeZone(String timeZone) { this.timeZone = timeZone; return this; } }
三、創(chuàng)建有效時(shí)間注解
創(chuàng)建API有效時(shí)間注解
@Target
來(lái)指定ApiValidTime可以應(yīng)用的范圍,表示注解可以用在那些地方上
@Retention(RetentionPolicy.RUNTIME)
注解的生命周期,生效時(shí)間
@Retention(RetentionPolicy)
RetentionPolicy.SOURCE 僅編譯期
RetentionPolicy.CLASS (默認(rèn)) 僅class文件
RetentionPolicy.RUNTIME 運(yùn)行期
通常我們自定義的Annotation都是RUNTIME所以,務(wù)必加上@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType)
- ELementType.TYPE 類(lèi)或接口
- ELementType.FIELD 字段
- ElementType.METHOD 方法
- ElementType.PARAMETER 方法參數(shù)
- ElementType.CONSTRUCTOR 構(gòu)造方法
在注解中定義2個(gè)屬性,time
和 TIME_ZONE_ENUM
,
time表示接口生效時(shí)間格式為"yyyy-MM-dd HH:mm:ss",
TIME_ZONE_ENUM指地區(qū)枚舉類(lèi)TimeZoneEnum
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; ? @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ApiValidTime { /** * PST 時(shí)間 * @return pst時(shí)間 yyyy-MM-dd HH:mm:ss */ String time() default ""; ? /** * 地區(qū) timeZone * @return 地區(qū) */ TimeZoneEnum TIME_ZONE_ENUM(); }
四、攔截器
1、創(chuàng)建ApiValidTime攔截器
處理邏輯:
1、攔截設(shè)置路徑的請(qǐng)求
2、獲取攔截到的方法HandlerMethod
3、判斷方法對(duì)應(yīng)的類(lèi)上有沒(méi)有ApiValidTime注解,沒(méi)有在去判斷方法上有沒(méi)有ApiValidTime注解
4、沒(méi)有ApiValidTime注解,就放行
5、如果有,就獲取ApiValidTime注解中的time
和TIME_ZONE_ENUM
屬性值
6、獲取當(dāng)前TIME_ZONE_ENUM
對(duì)應(yīng)時(shí)區(qū)的時(shí)間
7、TIME_ZONE_ENUM
對(duì)應(yīng)時(shí)區(qū)的時(shí)間,與time
的時(shí)間比較,TIME_ZONE_ENUM
對(duì)應(yīng)時(shí)區(qū)的時(shí)間小于time
的時(shí)間放行,大于攔截,攔截后將自定的響應(yīng)性信息falseResult返回
這里我直接根據(jù)地區(qū)去獲取地區(qū)所在時(shí)區(qū)的時(shí)間了,有興趣的jym可以試試其他方式。
import liu.qingxu.constant.ApiValidTime; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Objects; ? /** * @module 接口有效時(shí)間攔截器 * @author: qingxu.liu * @date: 2022-10-10 22:01 * @copyright **/ @Component @Slf4j public class ApiValidTimeInterceptor implements HandlerInterceptor { ? @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判斷是否需要攔截 if (!(handler instanceof HandlerMethod)){ return true; } HandlerMethod hm = (HandlerMethod) handler; //獲取類(lèi)上的注解 ApiValidTime annotation = hm.getBeanType().getAnnotation(ApiValidTime.class); if (Objects.isNull(annotation)){ //類(lèi)上沒(méi)有獲取方法上的 annotation = hm.getMethod().getAnnotation(ApiValidTime.class); } //判斷類(lèi)上是否有打該注解 //boolean clazzAnnotationPresent = hm.getBeanType().isAnnotationPresent(ApiValidTime.class); //判斷類(lèi)上或注解上有沒(méi)有注解 if (Objects.isNull(annotation)){ //沒(méi)有放行 return true; }else { //有注解,獲取注解信息,比較時(shí)間大小 String time = annotation.time(); String region = annotation.TIME_ZONE_ENUM().getRegion(); ZoneId pstZoneId = ZoneId.of(region); DateTimeFormatter pstDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(pstZoneId); ZonedDateTime pstZonedDateTime = ZonedDateTime.parse(time, pstDateTimeFormatter); //獲取所在時(shí)間的時(shí)間戳 long nowTime = ZonedDateTime.now(pstZoneId).toInstant().toEpochMilli(); boolean checkResult = pstZonedDateTime.toInstant().toEpochMilli() > nowTime; if (checkResult){ return true; }else { falseResult(response); return false; } } } /** * 攔截后處理 */ private void falseResult(HttpServletResponse response) throws IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.getWriter().println("This event has ended, please do not visit again!"); } }
2、注冊(cè)攔截器,設(shè)置攔截路徑
攔截路徑為:/activity/h5/...下的所有路徑
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; ? @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { ? final ApiValidTimeInterceptor apiValidTimeInterceptor; public WebMvcConfig(ApiValidTimeInterceptor apiValidTimeInterceptor) { this.apiValidTimeInterceptor = apiValidTimeInterceptor; } ? @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(apiValidTimeInterceptor) .addPathPatterns("/activity/h5**"); //攔截路徑 ? } }
五、驗(yàn)證結(jié)果
新建一個(gè)Controller
@RestController @RequestMapping("/activity/h5") public class ApiValidController { ? @GetMapping("/test/run") @ApiValidTime(time = "2023-02-28 10:00:00", TIME_ZONE_ENUM = Asia_Shanghai) public void runTest(){ System.out.println(new Date()); } }
現(xiàn)在是北京時(shí)間:2023-02-28 21:30:45 已經(jīng)過(guò)接口有效時(shí)間
重新設(shè)置接口時(shí)間為:2023-04-20 10:00:00,重啟服務(wù),再次請(qǐng)求:
@GetMapping("/test/run") @ApiValidTime(time = "2023-04-20 10:00:00", TIME_ZONE_ENUM = Asia_Shanghai) public void runTest(){ System.out.println(new Date()); }
此時(shí)就可以看到?jīng)]有接口過(guò)期提醒,在控制臺(tái)也可以看到時(shí)間打印了
以上就是SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot設(shè)置接口有效時(shí)間的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 在SpringBoot接口中正確地序列化時(shí)間字段的方法
- SpringBoot項(xiàng)目中Date類(lèi)型數(shù)據(jù)在接口返回的時(shí)間不正確的問(wèn)題解決
- springboot配置請(qǐng)求超時(shí)時(shí)間(Http會(huì)話(huà)和接口訪(fǎng)問(wèn))
- SpringBoot優(yōu)化接口響應(yīng)時(shí)間的九個(gè)技巧
- Springboot項(xiàng)目長(zhǎng)時(shí)間不進(jìn)行接口操作,提示HikariPool-1警告的解決
- SpringBoot接口返回的數(shù)據(jù)時(shí)間與實(shí)際相差8小時(shí)問(wèn)題排查方式
相關(guān)文章
spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決)
這篇文章主要介紹了spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03java實(shí)現(xiàn)表格tr拖動(dòng)的實(shí)例(分享)
下面小編就為大家分享一篇java實(shí)現(xiàn)表格tr拖動(dòng)的實(shí)例。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn)
這篇文章主要介紹了Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Mybatis使用foreach批量更新數(shù)據(jù)報(bào)無(wú)效字符錯(cuò)誤問(wèn)題
這篇文章主要介紹了Mybatis使用foreach批量更新數(shù)據(jù)報(bào)無(wú)效字符錯(cuò)誤問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08- 在Java中,生成隨機(jī)數(shù)有兩種方法。1是使用Random類(lèi)。2是使用Math類(lèi)中的random方法??聪旅娴睦邮褂冒?/div> 2013-11-11
Spring集成PageHelper的簡(jiǎn)單用法示例
這篇文章主要介紹了Spring集成PageHelper的簡(jiǎn)單用法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08IDEA 中 maven 的 Lifecycle 和Plugins&n
IDEA 主界面右側(cè) Maven 標(biāo)簽欄有同樣的命令,比如 install,既在 Plugins 中存在,也在 Lifecycle中存在,到底選哪個(gè)?二者又有什么區(qū)別呢?下面小編給大家介紹下IDEA 中 maven 的 Lifecycle 和Plugins 的區(qū)別,感興趣的朋友一起看看吧2023-03-03最新評(píng)論