redis实现接口限流策略

pull/254/head
xjs 3 years ago
parent 0e994a168c
commit 0914ee4f37

@ -0,0 +1,35 @@
package com.xjs.annotation;
import com.xjs.enums.InterfaceLimitType;
import java.lang.annotation.*;
/**
*
* @author xiejs
* @since 2022-05-16
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter {
/**
* key
*/
String key() default "rate_limit:";
/**
* ,
*/
int time() default 60;
/**
*
*/
int count() default 100;
/**
*
*/
InterfaceLimitType limitType() default InterfaceLimitType.DEFAULT;
}

@ -0,0 +1,70 @@
package com.xjs.aop;
import com.ruoyi.common.core.utils.ip.IpUtils;
import com.xjs.annotation.RateLimiter;
import com.xjs.enums.InterfaceLimitType;
import com.xjs.exception.BusinessException;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
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 java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
/**
* aop
* @author xiejs
* @since 2022-05-16
*/
@Aspect
@Component
@Log4j2
public class RateLimiterAspect {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private RedisScript<Long> limitScript;
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
String key = rateLimiter.key();
int time = rateLimiter.time();
int count = rateLimiter.count();
String combineKey = getCombineKey(rateLimiter, point);
List<Object> keys = Collections.singletonList(combineKey);
try {
Long number = redisTemplate.execute(limitScript, keys, count, time);
if (number==null || number.intValue() > count) {
throw new BusinessException("访问过于频繁,请稍候再试");
}
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key);
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("服务器限流异常,请稍候再试");
}
}
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
StringBuilder stringBuffer = new StringBuilder(rateLimiter.key());
if (rateLimiter.limitType() == InterfaceLimitType.IP) {
stringBuffer.append(IpUtils.getIpAddr(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest())).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
return stringBuffer.toString();
}
}

@ -0,0 +1,18 @@
package com.xjs.enums;
/**
*
* @author xiejs
* @since 2022-05-16
*/
public enum InterfaceLimitType {
/**
*
*/
DEFAULT,
/**
* IP
*/
IP
}

@ -0,0 +1,23 @@
package com.xjs.script;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
/**
* redis
* @author xiejs
* @since 2022-05-16
*/
@Configuration
public class RedisScript {
@Bean
public DefaultRedisScript<Long> limitScript() {
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/limit.lua")));
redisScript.setResultType(Long.class);
return redisScript;
}
}

@ -0,0 +1,12 @@
local key = KEYS[1]
local count = tonumber(ARGV[1])
local time = tonumber(ARGV[2])
local current = redis.call('get', key)
if current and tonumber(current) > count then
return tonumber(current)
end
current = redis.call('incr', key)
if tonumber(current) == 1 then
redis.call('expire', key, time)
end
return tonumber(current)

@ -10,6 +10,7 @@ import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresLogin;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.xjs.annotation.RateLimiter;
import com.xjs.copywriting.domain.CopyWriting;
import com.xjs.copywriting.domain.RequestBody;
import com.xjs.copywriting.factory.CopyWritingFactory;
@ -29,6 +30,7 @@ import java.util.Optional;
/**
* controller
*
* @author xiejs
* @since 2021-12-27
*/
@ -84,7 +86,7 @@ public class CopyWritingController extends BaseController {
//清理重复内容
int i = copyWritingService.deleteRepeatData();
log.info("清理文案重复数:"+i);
log.info("清理文案重复数:" + i);
return R.ok(copyWriting);
}
@ -93,6 +95,7 @@ public class CopyWritingController extends BaseController {
@ApiOperation("删除重复文案内容")
@RequiresPermissions("openapi:copywriting:remove")
@Log(title = "删除重复文案", businessType = BusinessType.DELETE)
@RateLimiter(count = 1, time = 1)
public AjaxResult deleteRepeatData() {
int count = copyWritingService.deleteRepeatData();
return AjaxResult.success(count);
@ -152,6 +155,7 @@ public class CopyWritingController extends BaseController {
@ApiOperation("文案列表")
@RequiresPermissions("openapi:copywriting:list")
@GetMapping("/list")
@RateLimiter(count = 1, time = 1)
public TableDataInfo list(@Validated({SelectGroup.class}) CopyWriting copyWriting) {
startPage();
List<CopyWriting> list = copyWritingService.selectCopyWritingList(copyWriting);
@ -188,6 +192,7 @@ public class CopyWritingController extends BaseController {
@Log(title = "文案管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@ApiOperation("删除文案")
@RateLimiter(count = 1, time = 1)
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(copyWritingService.deleteCopyWritingByIds(ids));
}

@ -1,7 +1,6 @@
package com.xjs.mall.product.vo.sku;
import lombok.Data;
import lombok.ToString;
/**
* Sku Id VO Attr
@ -9,7 +8,6 @@ import lombok.ToString;
* @since 2022-05-12
*/
@Data
@ToString
public class AttrValueWithSkuIdVO {
private String attrValue;

Loading…
Cancel
Save