SpringBoot 根据各地区时间设置接口有效时间

戳上方蓝字“Java笔记虾”关注!

之前接到需求,需要给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表示时区

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

SpringBoot 根据各地区时间设置接口有效时间
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个属性,time和 TIME_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拦截器

处理逻辑:

  • 拦截设置路径的请求
  • 获取拦截到的方法HandlerMethod
  • 判断方法对应的类上有没有ApiValidTime注解,没有在去判断方法上有没有ApiValidTime注解
  • 没有ApiValidTime注解,就放行
  • 如果有,就获取ApiValidTime注解中的time和TIME_ZONE_ENUM属性值
  • 获取当前TIME_ZONE_ENUM对应时区的时间
  • 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 已经过接口有效时间

SpringBoot 根据各地区时间设置接口有效时间

重新设置接口时间为: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 根据各地区时间设置接口有效时间

感谢阅读,希望对你有所帮助 :)   

juejin.cn/post/7205162789157142586

后端专属技术群

构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!

文明发言,以交流技术职位内推行业探讨为主

广告人士勿入,切勿轻信私聊,防止被骗

SpringBoot 根据各地区时间设置接口有效时间

加我好友,拉你进群

原文始发于微信公众号(Java笔记虾):SpringBoot 根据各地区时间设置接口有效时间

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/203035.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!