之前接到需求,需要给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个属性,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
已经过接口有效时间

重新设置接口时间为: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());
}
此时就可以看到没有接口过期提醒,在控制台也可以看到时间打印了


感谢阅读,希望对你有所帮助 :)
juejin.cn/post/7205162789157142586
后端专属技术群 构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!
文明发言,以
交流技术
、职位内推
、行业探讨
为主广告人士勿入,切勿轻信私聊,防止被骗
加我好友,拉你进群
原文始发于微信公众号(Java笔记虾):SpringBoot 根据各地区时间设置接口有效时间
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/203035.html