增加限流的操作类型,补充CommonController注解

This commit is contained in:
D 2024-01-25 10:58:24 +08:00
parent ad1b71e32e
commit 6cf353c31e
5 changed files with 70 additions and 27 deletions

37
doc/限流逻辑.drawio Normal file
View File

@ -0,0 +1,37 @@
<mxfile host="65bd71144e">
<diagram id="PZYBk4sDCuIX38xMYcUk" name="第 1 页">
<mxGraphModel dx="900" dy="563" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="4" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="3">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="2" value="标记有RateLimiter注解的方法会被拦截" style="html=1;" vertex="1" parent="1">
<mxGeometry x="160" y="80" width="380" height="50" as="geometry"/>
</mxCell>
<mxCell id="6" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="3" target="5">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="3" value="获取注解上的时间和次数" style="html=1;" vertex="1" parent="1">
<mxGeometry x="160" y="150" width="380" height="50" as="geometry"/>
</mxCell>
<mxCell id="8" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="5" target="7">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="5" value="&amp;nbsp;通过拼接{KEY}-{IP/USERID/DEPTID}-{ClassName}-{MethodName}形成rediskey" style="html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="230" width="500" height="50" as="geometry"/>
</mxCell>
<mxCell id="10" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="7" target="9">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="7" value="通过redisTemplate.excute来检测time时间内最大请求次数" style="html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="310" width="500" height="50" as="geometry"/>
</mxCell>
<mxCell id="9" value="通过返回的number再次确认请求次数" style="html=1;" vertex="1" parent="1">
<mxGeometry x="100" y="390" width="500" height="50" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@ -25,6 +25,7 @@ import com.ruoyi.framework.config.ServerConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@ -85,7 +86,7 @@ public class CommonController {
*/
@Operation(summary = "通用上传请求(单个)")
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception {
public AjaxResult uploadFile(@RequestBody MultipartFile file) throws Exception {
try {
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
@ -108,7 +109,7 @@ public class CommonController {
*/
@Operation(summary = "通用上传请求(多个)")
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files)
public AjaxResult uploadFiles(@RequestBody List<MultipartFile> files)
throws Exception {
try {
// 上传文件路径

View File

@ -5,6 +5,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.enums.LimitType;

View File

@ -6,8 +6,7 @@ package com.ruoyi.common.enums;
* @author ruoyi
*/
public enum LimitType
{
public enum LimitType {
/**
* 默认策略全局限流
*/
@ -16,5 +15,15 @@ public enum LimitType
/**
* 根据请求者IP进行限流
*/
IP
IP,
/**
* 根据请求者的用户ID进行限流
*/
USER,
/**
* 根据请求者的部门进行限流
*/
DEPT,
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.framework.aspectj;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@ -13,9 +14,11 @@ 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 com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
@ -26,8 +29,7 @@ import com.ruoyi.common.utils.ip.IpUtils;
*/
@Aspect
@Component
public class RateLimiterAspect
{
public class RateLimiterAspect {
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
private RedisTemplate<Object, Object> redisTemplate;
@ -35,50 +37,43 @@ public class RateLimiterAspect
private RedisScript<Long> limitScript;
@Autowired
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
{
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Autowired
public void setLimitScript(RedisScript<Long> limitScript)
{
public void setLimitScript(RedisScript<Long> limitScript) {
this.limitScript = limitScript;
}
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
{
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
int time = rateLimiter.time();
int count = rateLimiter.count();
String combineKey = getCombineKey(rateLimiter, point);
List<Object> keys = Collections.singletonList(combineKey);
try
{
try {
Long number = redisTemplate.execute(limitScript, keys, count, time);
if (StringUtils.isNull(number) || number.intValue() > count)
{
if (StringUtils.isNull(number) || number.intValue() > count) {
throw new ServiceException("访问过于频繁,请稍候再试");
}
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
}
catch (ServiceException e)
{
} catch (ServiceException e) {
throw e;
}
catch (Exception e)
{
} catch (Exception e) {
throw new RuntimeException("服务器限流异常,请稍候再试");
}
}
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
{
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP)
{
if (rateLimiter.limitType() == LimitType.IP) {
stringBuffer.append(IpUtils.getIpAddr()).append("-");
} else if (rateLimiter.limitType() == LimitType.USER) {
stringBuffer.append(SecurityUtils.getUserId()).append("-");
} else if (rateLimiter.limitType() == LimitType.DEPT) {
stringBuffer.append(SecurityUtils.getDeptId()).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();