redis命令Incr做计数器 + 切点切面
Redis Incr 命令将 key 中储存的数字值增一。
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
package com.example.apidemo.config.aspect; import com.example.apidemo.redis.LocalCache; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Objects; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Date; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @Aspect @Component public class DoneTimeAspect { @Autowired private LocalCache localCache; /** * 当方法符合切点规则不符合环绕通知的规则时候,执行的顺序如下 * @Before → @After→ @AfterRunning (如果有异常→@AfterThrowing) * * 当方法符合切点规则并且符合环绕通知的规则时候,执行的顺序如下 * @Around → @Before → @Around → @After执行 ProceedingJoinPoint.proceed() 之后的操作→@AfterRunning(如果有异常→@AfterThrowing) */ @Before("execution (* com.example.apidemo.controller.*.*(..))") public void before(JoinPoint joinPoint) throws Exception { System.out.println("======前置通知--拦截配置的package的controller:" + Arrays.toString(joinPoint.getArgs()) + LocalDateTime.now()); //最简单的接口重复请求处理方法 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); String sessionId = attributes.getSessionId(); // 用户请求唯一标识sessionId String uri = attributes.getRequest().getServletPath(); // 用户请求的uri String key = sessionId + "-" + uri; // 针对用户对应接口的唯一key System.out.println("key==="+ key + LocalDateTime.now()); Object object = localCache.getCache(key); // 将生成的key存储在redis中,每次请求一次就增加一次 System.out.println("object==="+ object + "==" + LocalDateTime.now()); if (Objects.isNull(object) || Integer.parseInt(object.toString()) <=2 ) { localCache.putIncrKey(key, 1L); //设置2分钟 过期 return; } if (Integer.parseInt(object.toString()) >2) { throw new Exception("接口在2分钟内重复请求超过2次"); //再写一个全局ExceptionHandler,返回给前端 } } @Around("execution (* com.example.apidemo.controller.*.*(..)) && @annotation(doneTime))") public Object around(ProceedingJoinPoint joinPoint, DoneTime doneTime) throws Throwable { System.out.println("======环绕通知--:"+ Arrays.toString(joinPoint.getArgs())); if (doneTime.param().equals("IndexController")) { return "切面直接拦截==IndexController"; } Object o = joinPoint.proceed(); //joinPoint.proceed()会继续走切面所在的方法 System.out.println("切面走proceed方法结束时间是:"+new Date()) ; return o; } }
@Component @Slf4j public class LocalCache { @Autowired private StringRedisTemplate stringRedisTemplate;
public void putIncrKey(String key, Long value) {
Long num = stringRedisTemplate.opsForValue().increment(key, value);
log.info("increment===key|{},num|{},time|{}", key, num, LocalDateTime.now());
//increment 命令传入value 为1就加1, 为5就加5
if (num != null) {
stringRedisTemplate.expire(key,2, TimeUnit.MINUTES);
}
}
}
学海无涯 代码作伴