限制用户单位时间请求接口次数(aop和filter实现)

    xiaoxiao2022-07-07  146

    在项目中实现单位时间内限制用户访问指定接口次数问题,如有错误烦请指正交流

    如限制用户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"; } }

    1过滤器方式

    package com.xuxu.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import com.xuxu.limit.LimitByMap; @WebFilter(filterName="MyFilter",urlPatterns="/index") public class MyFilter implements Filter{ @Autowired private LimitByMap limitMap; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestURI = httpRequest.getRequestURI(); String userID = "123456"; String key = userID+requestURI; limitMap.limitRequest(key,10, 10000L); chain.doFilter(request, response); } }

    启动类上加入@ServletComponentScan 过滤器生效

    @SpringBootApplication @ServletComponentScan public class LimitUser01Application { public static void main(String[] args) { SpringApplication.run(LimitUser01Application.class, args); } }

    2自定义注解加AOP方式

    自定义注解

    @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); } }

     

     

    最新回复(0)