如限制用户10秒中内只能请求某一接口10次 这里我使用的是map方式存储计数,如果并发量大考虑放入redis中
核心限制类
package com.xuxu.limit; import java.util.concurrent.ConcurrentHashMap; import org.springframework.stereotype.Component; @Component public class LimitByMap { //全局MAP key为userId+URI value为CountParam 统计对象 记录时间和次数 public static ConcurrentHashMap<String, CountParam> cacheMap = new ConcurrentHashMap<>(); /** * * @param key 自定义key userId+URI * @param num 自定义限制请求次数 超出次数后限制访问 * @param limitTime 自定义限制时间,限制时间内限制访问次数 */ public void limitRequest(String key,int num,Long limitTime){ //1通过key获取到countPatam对象 CountParam countParam = cacheMap.get(key); //2判断对象是否为空,如果为空则代表第一次访问 如果不为空则代表之前请求过 if(countParam!=null){ //3获取时间,用当前时间减去最后一次访问时间,如果规定时间则清零访问次数,小于则累加计数 Long time = System.currentTimeMillis()-countParam.getTime(); int currentCount = countParam.getCount(); if(time<limitTime){ //4如果累计次数大于10,证明用户在限制时间内访问过多 if(currentCount>=num){ System.out.println("访问超出限制次数"); return; }else{ countParam.setCount(++currentCount); } }else{ countParam.setCount(1); } System.out.println(countParam.getCount()); countParam.setTime(System.currentTimeMillis()); }else{ countParam = new CountParam(); countParam.setCount(1); countParam.setTime(System.currentTimeMillis()); } cacheMap.put(key, countParam); } }统计对象
package com.xuxu.limit; public class CountParam { private Long time; private int count; public Long getTime() { return time; } public void setTime(Long time) { this.time = time; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } }要被限制的接口
package com.xuxu.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.xuxu.annotation.MyLimit; @RestController public class UserController { @RequestMapping("/index") public String index(){ return "index"; } }启动类上加入@ServletComponentScan 过滤器生效
@SpringBootApplication @ServletComponentScan public class LimitUser01Application { public static void main(String[] args) { SpringApplication.run(LimitUser01Application.class, args); } }自定义注解
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyLimit { long limitTime() default 60000; int num() default 50; }切面类
@Aspect @Component public class MyLimitAop { @Autowired private LimitByMap limitMap; @Pointcut("execution(* com.xuxu.controller.*.*(..))") public void cutPoint(){ } @Around("cutPoint()") public Object limit(ProceedingJoinPoint joinPoint) throws Throwable{ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); if(method.isAnnotationPresent(MyLimit.class)){ MyLimit myLimit = method.getAnnotation(MyLimit.class); long limitTime = myLimit.limitTime(); int num=myLimit.num(); String userID = "123456"; ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String requestURI = request.getRequestURI(); String key = userID+requestURI; limitMap.limitRequest(key,num,limitTime); } return joinPoint.proceed(); } }controller中方法上加入注解
@RequestMapping("/index") @MyLimit(limitTime=10000L,num=10) public String index(){ return "index"; }启动类上加入aop支持
@SpringBootApplication @EnableAspectJAutoProxy public class LimitUser01Application { public static void main(String[] args) { SpringApplication.run(LimitUser01Application.class, args); } }