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

 

posted @ 2022-08-12 10:45  威兰达  阅读(469)  评论(0编辑  收藏  举报