java 手写 拦截器_手写一个注解实现接口单位时间内的访问频率的拦截器

目标

相信大家都听过接口安全,接口限流等这些词语,那么本篇文章就是从最基本的问题开始,带大家手写一个控制接口单位时间内访问频率的demo。好了,下面开始上代码。

环境+依赖

spring boot工程就不在此搭建了,小编直接贴出核心依赖org.springframework.bootspring-boot-starter-data-redis2.3.0.RELEASEorg.apache.commonscommons-pool22.4.2org.springframework.bootspring-boot-starter-thymeleaforg.springframework.bootspring-boot-starter-web

里面有用到redis,具体的配置可以参考小编之前的文章springboot整合redis,此处不再单独列出来了。

自定义注解 + 拦截器自定义注解@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ApiLimit { //time时间内请求的最大次数 int count(); //时间段内,单位:s int time(); }拦截器public class ApiInterceptor implements HandlerInterceptor{ @Autowired private RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); ApiLimit apiLimit = method.getAnnotation(ApiLimit.class); if(!ObjectUtils.isEmpty(apiLimit)) { int count = apiLimit.count(); int time = apiLimit.time(); String ip = request.getRemoteAddr(); String requestURI = request.getRequestURI(); String redisKey = "apiKey_" + ip + "_" + requestURI; System.out.println("redisKey======>" + redisKey); if (ObjectUtils.isEmpty(redisTemplate.opsForValue().get(redisKey))) { AtomicInteger atomicInteger = new AtomicInteger(1); redisTemplate.opsForValue().set(redisKey, atomicInteger, time, TimeUnit.SECONDS); System.out.println("当前访问次数:" + ((AtomicInteger) redisTemplate.opsForValue().get(redisKey)).get()); } else { AtomicInteger atomicInteger = (AtomicInteger) redisTemplate.opsForValue().get(redisKey); if (atomicInteger.incrementAndGet() > count) { throw new RuntimeException("访问太频繁了,请休息一会"); } Long expire = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS); redisTemplate.opsForValue().set(redisKey, atomicInteger, expire ,TimeUnit.SECONDS); System.out.println("当前访问次数:" + ((AtomicInteger) redisTemplate.opsForValue().get(redisKey)).get()); } } else { return true; } } return true; } }

ip的获取大家可以借鉴网上的工具,此处为测试就简写了。拦截器配置

拦截器写好之后,需要将它注册到spring中@Configuration public class WebMvcConfig implements WebMvcConfigurer{ @Bean public ApiInterceptor apiInterceptor(){ return new ApiInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry){ //这里我们添加了一个测试的路径 registry.addInterceptor(apiInterceptor()).addPathPatterns("/test/limit"); } }

测试类

只需要在需要拦截的接口上加上@ApiLimit注解,定义好时间和访问次数即可。@Controller @RequestMapping("/test") public class TestController{ @GetMapping("/limit") @ResponseBody @ApiLimit(count = 5, time = 10) public String get() { return "hello world !!!"; } }

测试

我们先连续访问这个url,10s后再次访问。结果如下

3f02b6796b87db106526dae97b9d030e.png

连续访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值