1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| package cn.gloduck.gmall.limit.aspect;
import cn.gloduck.gmall.limit.annotation.Limit; import cn.gloduck.gmall.limit.enums.LimitType; import cn.gloduck.gmall.limit.exception.LimitAccessException; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.List; import java.util.Objects;
@Component @Aspect public class RedisLimitAspect { private Logger logger = LoggerFactory.getLogger(RedisLimitAspect.class); @Autowired private RedisTemplate<String, Object> redisTemplate; private final static String LIMIT_SCRIPT = "local c" + "\nc = redis.call('get',KEYS[1])" + "\nif c and tonumber(c) > tonumber(ARGV[1]) then" + "\nreturn c;" + "\nend" + "\nc = redis.call('incr',KEYS[1])" + "\nif tonumber(c) == 1 then" + "\nredis.call('expire',KEYS[1],ARGV[2])" + "\nend" + "\nreturn c;";
@Pointcut("@annotation(limit)") public void pointcut(Limit limit) { }
@Around(value = "pointcut(limit)", argNames = "joinPoint,limit") public Object around(ProceedingJoinPoint joinPoint,Limit limit) throws Throwable { LimitType type = limit.type(); RedisScript<Long> script =new DefaultRedisScript<>(LIMIT_SCRIPT, Long.class); List<String> key = Collections.singletonList(type.generateKey(getRequest())); Number number = redisTemplate.execute(script, key, limit.count(), limit.timeout()); if(number != null && number.intValue() <= limit.count()){ logger.info("第{}次访问接口,key为{}", number, key); return joinPoint.proceed(); } else { throw new LimitAccessException("访问超出限制"); } }
public HttpServletRequest getRequest() { return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); } }
|