SpringBoot根据各地区时间设置接口有效时间的实现方式

 更新时间:2024年01月31日 11:41:27   作者:不瑶碧莲  
这篇文章给大家介绍了SpringBoot根据各地区时间设置接口有效时间的实现方式,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下

之前接到需求,需要给APP内的H5活动的接口加上时效性,防止活动后还有用户调用接口;

因为有些H5活动是长期的,有些是短期的,所以我需要做好区分,因为我们的app是国外用户在用的,所以还要考虑的时区的问题;

想了一下决定用注解+`拦截器的方式去实现

默认已经创建好了SpringBoot项目

一、获取不同时区的时间方式

1、通过时区获取所在时区时间

/**
* 获得东八区时间
*
* @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、通过地区获取所在时区时间

根据ZoneId 获取当地时间

ZonedDateTime是结合了LocalDateTime类与 ZoneId 类。它用于表示具有时区(地区/城市,如欧洲/巴黎)的完整日期(年,月,日)和时间(小时,分钟,秒,纳秒)

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、获取所在时区的时间戳

String region = "America/Los_Angeles";
ZoneId pstZoneId = ZoneId.of(region);
long nowTime = ZonedDateTime.now(pstZoneId).toInstant().toEpochMilli(); //nowTime时间戳

当然还有其他方式获取得到,网上有很多工具类~~~

二、创建地区/时区枚举类

region属性表示时间,timeZone表示时区

还有一点要注意的,一些国家有冬令时和夏令时的区分,比如美国、德国、法国等,这里我同一用了协同世界时

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"),//印度尼西亚-雅加达
    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;
    }
}

三、创建有效时间注解

创建API有效时间注解

@Target来指定ApiValidTime可以应用的范围,表示注解可以用在那些地方上

@Retention(RetentionPolicy.RUNTIME)注解的生命周期,生效时间

@Retention(RetentionPolicy)

  • RetentionPolicy.SOURCE 仅编译期

  • RetentionPolicy.CLASS (默认) 仅class文件

  • RetentionPolicy.RUNTIME 运行期

    通常我们自定义的Annotation都是RUNTIME所以,务必加上@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType)

  • ELementType.TYPE 类或接口
  • ELementType.FIELD 字段
  • ElementType.METHOD 方法
  • ElementType.PARAMETER 方法参数
  • ElementType.CONSTRUCTOR 构造方法

在注解中定义2个属性,timeTIME_ZONE_ENUM,

time表示接口生效时间格式为"yyyy-MM-dd HH:mm:ss",

TIME_ZONE_ENUM指地区枚举类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 时间
     * @return pst时间 yyyy-MM-dd HH:mm:ss
     */
    String time() default "";
​
    /**
     * 地区 timeZone
     * @return 地区
     */
    TimeZoneEnum TIME_ZONE_ENUM();
}

四、拦截器

1、创建ApiValidTime拦截器

处理逻辑:

1、拦截设置路径的请求

2、获取拦截到的方法HandlerMethod

3、判断方法对应的类上有没有ApiValidTime注解,没有在去判断方法上有没有ApiValidTime注解

4、没有ApiValidTime注解,就放行

5、如果有,就获取ApiValidTime注解中的timeTIME_ZONE_ENUM属性值

6、获取当前TIME_ZONE_ENUM对应时区的时间

7、TIME_ZONE_ENUM对应时区的时间,与time的时间比较,TIME_ZONE_ENUM对应时区的时间小于time的时间放行,大于拦截,拦截后将自定的响应性信息falseResult返回

这里我直接根据地区去获取地区所在时区的时间了,有兴趣的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 接口有效时间拦截器
 * @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 {
            //有注解,获取注解信息,比较时间大小
            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);
            //获取所在时间的时间戳
            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、注册拦截器,设置拦截路径

拦截路径为:/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**"); //拦截路径
​
    }
}

五、验证结果

新建一个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());
    }
}

现在是北京时间:2023-02-28 21:30:45 已经过接口有效时间

重新设置接口时间为:2023-04-20 10:00:00,重启服务,再次请求:

@GetMapping("/test/run")
@ApiValidTime(time = "2023-04-20 10:00:00", TIME_ZONE_ENUM = Asia_Shanghai)
public void runTest(){
    System.out.println(new Date());
}

此时就可以看到没有接口过期提醒,在控制台也可以看到时间打印了

以上就是SpringBoot根据各地区时间设置接口有效时间的实现方式的详细内容,更多关于SpringBoot设置接口有效时间的资料请关注脚本之家其它相关文章!

相关文章

最新评论