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个属性,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拦截器
处理逻辑:
1、拦截设置路径的请求
2、获取拦截到的方法HandlerMethod
3、判断方法对应的类上有没有ApiValidTime注解,没有在去判断方法上有没有ApiValidTime注解
4、没有ApiValidTime注解,就放行
5、如果有,就获取ApiValidTime注解中的time
和TIME_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设置接口有效时间的资料请关注脚本之家其它相关文章!