SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式
之前接到需求,需要給APP內(nèi)的H5活動的接口加上時(shí)效性,防止活動后還有用戶調(diào)用接口;
因?yàn)橛行〩5活動是長期的,有些是短期的,所以我需要做好區(qū)分,因?yàn)槲覀兊腶pp是國外用戶在用的,所以還要考慮的時(shí)區(qū)的問題;
想了一下決定用注解+`攔截器的方式去實(shí)現(xiàn)
默認(rèn)已經(jīng)創(chuàng)建好了SpringBoot項(xiàng)目
一、獲取不同時(shí)區(qū)的時(shí)間方式
1、通過時(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、通過地區(qū)獲取所在時(shí)區(qū)時(shí)間
根據(jù)ZoneId 獲取當(dāng)?shù)貢r(shí)間
ZonedDateTime是結(jié)合了LocalDateTime類與 ZoneId 類。它用于表示具有時(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)上有很多工具類~~~
二、創(chuàng)建地區(qū)/時(shí)區(qū)枚舉類
region屬性表示時(shí)間,timeZone表示時(shí)區(qū)
還有一點(diǎn)要注意的,一些國家有冬令時(shí)和夏令時(shí)的區(qū)分,比如美國、德國、法國等,這里我同一用了協(xié)同世界時(shí)

public enum TimeZoneEnum {
?
Asia_Shanghai("Asia/Shanghai","+8:00"),//中國-上海
Asia_Hong_Kong("Asia/Hong_Kong","+8:00"),//香港
Asia_Macau("Asia/Macau","+8:00"),//澳門
Asia_Taipei("Asia/Taipei","+8:00"),//臺灣
Asia_Singapore("Asia/Singapore","+8:00"),//新加坡
Asia_Bangkok("Asia/Bangkok","+7:00"),//泰國-曼谷
Asia_Calcutta("Asia/Calcutta","+5:30"),//印度-加爾各答
Asia_Tokyo("Asia/Tokyo","+9:00"),//日本-東京
Asia_Seoul("Asia/Seoul","+9:00"),//韓國-首爾
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"),//英國-倫敦
Europe_Paris("Europe/Paris","+1:00"),//法國-巴黎
Europe_Berlin("Europe/Berlin","+1:00"),//德國-柏林
Asia_Jakarta("Asia/Jakarta","+7:00"),//印度尼西亞-雅加達(dá)
Asia_Kuala_Lumpur("Asia/Kuala_Lumpur","+8:00");//馬來西亞-吉隆坡
?
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來指定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 類或接口
- 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ū)枚舉類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è)置路徑的請求
2、獲取攔截到的方法HandlerMethod
3、判斷方法對應(yīng)的類上有沒有ApiValidTime注解,沒有在去判斷方法上有沒有ApiValidTime注解
4、沒有ApiValidTime注解,就放行
5、如果有,就獲取ApiValidTime注解中的time和TIME_ZONE_ENUM屬性值
6、獲取當(dāng)前TIME_ZONE_ENUM對應(yīng)時(shí)區(qū)的時(shí)間
7、TIME_ZONE_ENUM對應(yīng)時(shí)區(qū)的時(shí)間,與time的時(shí)間比較,TIME_ZONE_ENUM對應(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;
//獲取類上的注解
ApiValidTime annotation = hm.getBeanType().getAnnotation(ApiValidTime.class);
if (Objects.isNull(annotation)){
//類上沒有獲取方法上的
annotation = hm.getMethod().getAnnotation(ApiValidTime.class);
}
//判斷類上是否有打該注解
//boolean clazzAnnotationPresent = hm.getBeanType().isAnnotationPresent(ApiValidTime.class);
//判斷類上或注解上有沒有注解
if (Objects.isNull(annotation)){
//沒有放行
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、注冊攔截器,設(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)過接口有效時(shí)間

重新設(shè)置接口時(shí)間為:2023-04-20 10:00:00,重啟服務(wù),再次請求:
@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)]有接口過期提醒,在控制臺也可以看到時(shí)間打印了


以上就是SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot設(shè)置接口有效時(shí)間的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決)
這篇文章主要介紹了spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
java實(shí)現(xiàn)表格tr拖動的實(shí)例(分享)
下面小編就為大家分享一篇java實(shí)現(xiàn)表格tr拖動的實(shí)例。具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn)
這篇文章主要介紹了Spring Data Jpa 復(fù)合主鍵的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Mybatis使用foreach批量更新數(shù)據(jù)報(bào)無效字符錯(cuò)誤問題
這篇文章主要介紹了Mybatis使用foreach批量更新數(shù)據(jù)報(bào)無效字符錯(cuò)誤問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
在Java中,生成隨機(jī)數(shù)有兩種方法。1是使用Random類。2是使用Math類中的random方法??聪旅娴睦邮褂冒?/div> 2013-11-11
IDEA 中 maven 的 Lifecycle 和Plugins&n
IDEA 主界面右側(cè) Maven 標(biāo)簽欄有同樣的命令,比如 install,既在 Plugins 中存在,也在 Lifecycle中存在,到底選哪個(gè)?二者又有什么區(qū)別呢?下面小編給大家介紹下IDEA 中 maven 的 Lifecycle 和Plugins 的區(qū)別,感興趣的朋友一起看看吧2023-03-03最新評論

