java 接口限制访问次数
1. 通过注解的形式实现通用接口访问次数限制
(1)pom.xml文件中引入expiringmap
<dependency> <groupId>net.jodah</groupId> <artifactId>expiringmap</artifactId> <version>0.5.10</version> </dependency>
(2)添加注解
@Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LimitRequest { //请求时间 long time() default 60 * 1000; //请求次数 int count() default Integer.MAX_VALUE; }
(3)添加注解对应解析类
@Aspect @Component public class LimitRequestAspect { private static ConcurrentHashMap<String, ExpiringMap<String, Integer>> hashMap = new ConcurrentHashMap<>(); @Pointcut("@annotation(limitRequest)") public void excudeService(LimitRequest limitRequest) { } @Around("excudeService(limitRequest)") public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable { RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest request = sra.getRequest(); ExpiringMap<String, Integer> map = hashMap.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build()); Integer count = map.getOrDefault(request.getRemoteAddr(), 0); if (count >= limitRequest.count()) { throw new BusinessException(500, "访问次数超过限制"); } else if (count == 0) { map.put(request.getRemoteAddr(), count + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS); } else { map.put(request.getRemoteAddr(), count + 1); } hashMap.put(request.getRequestURI(), map); Object result = pjp.proceed(); return result; } }
然后就可以在接口上添加对应的注解@LimitRequest(time=60*1000, count = 3) 来限制时间范围内请求次数了。
2. 针对特殊接口
思路:通过redis 失效时间来控制时间范围内请求次数
String commentKey = String.format("comment:%d:%d", comment.getBusinessId(), comment.getUserId()); Long count = redisTemplate.opsForValue().increment(commentKey); if (count > 10) { throw new BusinessException("发表评论过于频繁,休息下再操作吧~"); } redisTemplate.expire(commentKey, 30, TimeUnit.SECONDS);