3 changed files with 99 additions and 3 deletions
			
			
		- 
					82common/src/main/java/com/storeroom/aspect/LimitAspect.java
- 
					6common/src/main/java/com/storeroom/config/SwaggerConfig.java
- 
					14common/src/main/java/com/storeroom/utils/RequestHolder.java
| @ -0,0 +1,82 @@ | |||||
|  | package com.storeroom.aspect; | ||||
|  | 
 | ||||
|  | import com.google.common.collect.ImmutableList; | ||||
|  | import com.storeroom.annotaion.Limit; | ||||
|  | import com.storeroom.exception.BaseException; | ||||
|  | import com.storeroom.utils.RequestHolder; | ||||
|  | import com.storeroom.utils.StringUtils; | ||||
|  | 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.aspectj.lang.reflect.MethodSignature; | ||||
|  | import org.slf4j.Logger; | ||||
|  | import org.slf4j.LoggerFactory; | ||||
|  | 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 javax.servlet.http.HttpServletRequest; | ||||
|  | import java.lang.reflect.Method; | ||||
|  | 
 | ||||
|  | @Aspect | ||||
|  | @Component | ||||
|  | public class LimitAspect { | ||||
|  | 
 | ||||
|  |     private final RedisTemplate<Object,Object> redisTemplate; | ||||
|  |     private static final Logger logger = LoggerFactory.getLogger(LimitAspect.class); | ||||
|  | 
 | ||||
|  |     public LimitAspect(RedisTemplate<Object,Object> redisTemplate) { | ||||
|  |         this.redisTemplate = redisTemplate; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Pointcut("@annotation(com.storeroom.annotaion.Limit)") | ||||
|  |     public void pointcut() { | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Around("pointcut()") | ||||
|  |     public Object around(ProceedingJoinPoint joinPoint) throws Throwable { | ||||
|  |         HttpServletRequest request = RequestHolder.getHttpServletRequest(); | ||||
|  |         MethodSignature signature = (MethodSignature) joinPoint.getSignature(); | ||||
|  |         Method signatureMethod = signature.getMethod(); | ||||
|  |         Limit limit = signatureMethod.getAnnotation(Limit.class); | ||||
|  |         LimitType limitType = limit.limitType(); | ||||
|  |         String key = limit.key(); | ||||
|  |         if (StringUtils.isEmpty(key)) { | ||||
|  |             if (limitType == LimitType.IP) { | ||||
|  |                 key = StringUtils.getIp(request); | ||||
|  |             } else { | ||||
|  |                 key = signatureMethod.getName(); | ||||
|  |             } | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         ImmutableList<Object> keys = ImmutableList.of(StringUtils.join(limit.prefix(), "_", key, "_", request.getRequestURI().replaceAll("/","_"))); | ||||
|  | 
 | ||||
|  |         String luaScript = buildLuaScript(); | ||||
|  |         RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class); | ||||
|  |         Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period()); | ||||
|  |         if (null != count && count.intValue() <= limit.count()) { | ||||
|  |             logger.info("第{}次访问key为 {},描述为 [{}] 的接口", count, keys, limit.name()); | ||||
|  |             return joinPoint.proceed(); | ||||
|  |         } else { | ||||
|  |             throw new BaseException("访问次数受限制"); | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     /** | ||||
|  |      * 限流脚本 | ||||
|  |      */ | ||||
|  |     private String buildLuaScript() { | ||||
|  |         return "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;"; | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,14 @@ | |||||
|  | package com.storeroom.utils; | ||||
|  | 
 | ||||
|  | import org.springframework.web.context.request.RequestContextHolder; | ||||
|  | import org.springframework.web.context.request.ServletRequestAttributes; | ||||
|  | 
 | ||||
|  | import javax.servlet.http.HttpServletRequest; | ||||
|  | import java.util.Objects; | ||||
|  | 
 | ||||
|  | public class RequestHolder { | ||||
|  | 
 | ||||
|  |     public static HttpServletRequest getHttpServletRequest() { | ||||
|  |         return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); | ||||
|  |     } | ||||
|  | } | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue