增加限流的操作类型,补充CommonController注解
This commit is contained in:
parent
ad1b71e32e
commit
6cf353c31e
37
doc/限流逻辑.drawio
Normal file
37
doc/限流逻辑.drawio
Normal 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="&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>
|
@ -25,6 +25,7 @@ import com.ruoyi.framework.config.ServerConfig;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -85,7 +86,7 @@ public class CommonController {
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "通用上传请求(单个)")
|
@Operation(summary = "通用上传请求(单个)")
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public AjaxResult uploadFile(MultipartFile file) throws Exception {
|
public AjaxResult uploadFile(@RequestBody MultipartFile file) throws Exception {
|
||||||
try {
|
try {
|
||||||
// 上传文件路径
|
// 上传文件路径
|
||||||
String filePath = RuoYiConfig.getUploadPath();
|
String filePath = RuoYiConfig.getUploadPath();
|
||||||
@ -108,7 +109,7 @@ public class CommonController {
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "通用上传请求(多个)")
|
@Operation(summary = "通用上传请求(多个)")
|
||||||
@PostMapping("/uploads")
|
@PostMapping("/uploads")
|
||||||
public AjaxResult uploadFiles(List<MultipartFile> files)
|
public AjaxResult uploadFiles(@RequestBody List<MultipartFile> files)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
try {
|
try {
|
||||||
// 上传文件路径
|
// 上传文件路径
|
||||||
|
@ -5,6 +5,7 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.enums.LimitType;
|
import com.ruoyi.common.enums.LimitType;
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ package com.ruoyi.common.enums;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public enum LimitType
|
public enum LimitType {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* 默认策略全局限流
|
* 默认策略全局限流
|
||||||
*/
|
*/
|
||||||
@ -16,5 +15,15 @@ public enum LimitType
|
|||||||
/**
|
/**
|
||||||
* 根据请求者IP进行限流
|
* 根据请求者IP进行限流
|
||||||
*/
|
*/
|
||||||
IP
|
IP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据请求者的用户ID进行限流
|
||||||
|
*/
|
||||||
|
USER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据请求者的部门进行限流
|
||||||
|
*/
|
||||||
|
DEPT,
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.ruoyi.framework.aspectj;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Before;
|
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.RedisTemplate;
|
||||||
import org.springframework.data.redis.core.script.RedisScript;
|
import org.springframework.data.redis.core.script.RedisScript;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.RateLimiter;
|
import com.ruoyi.common.annotation.RateLimiter;
|
||||||
import com.ruoyi.common.enums.LimitType;
|
import com.ruoyi.common.enums.LimitType;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
import com.ruoyi.common.utils.ip.IpUtils;
|
||||||
|
|
||||||
@ -26,8 +29,7 @@ import com.ruoyi.common.utils.ip.IpUtils;
|
|||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
public class RateLimiterAspect
|
public class RateLimiterAspect {
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
||||||
|
|
||||||
private RedisTemplate<Object, Object> redisTemplate;
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
@ -35,50 +37,43 @@ public class RateLimiterAspect
|
|||||||
private RedisScript<Long> limitScript;
|
private RedisScript<Long> limitScript;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
|
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate) {
|
||||||
{
|
|
||||||
this.redisTemplate = redisTemplate;
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setLimitScript(RedisScript<Long> limitScript)
|
public void setLimitScript(RedisScript<Long> limitScript) {
|
||||||
{
|
|
||||||
this.limitScript = limitScript;
|
this.limitScript = limitScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before("@annotation(rateLimiter)")
|
@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 time = rateLimiter.time();
|
||||||
int count = rateLimiter.count();
|
int count = rateLimiter.count();
|
||||||
|
|
||||||
String combineKey = getCombineKey(rateLimiter, point);
|
String combineKey = getCombineKey(rateLimiter, point);
|
||||||
List<Object> keys = Collections.singletonList(combineKey);
|
List<Object> keys = Collections.singletonList(combineKey);
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
Long number = redisTemplate.execute(limitScript, keys, count, time);
|
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("访问过于频繁,请稍候再试");
|
throw new ServiceException("访问过于频繁,请稍候再试");
|
||||||
}
|
}
|
||||||
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
|
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
|
||||||
}
|
} catch (ServiceException e) {
|
||||||
catch (ServiceException e)
|
|
||||||
{
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("服务器限流异常,请稍候再试");
|
throw new RuntimeException("服务器限流异常,请稍候再试");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
|
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
|
||||||
{
|
|
||||||
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
|
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
|
||||||
if (rateLimiter.limitType() == LimitType.IP)
|
if (rateLimiter.limitType() == LimitType.IP) {
|
||||||
{
|
|
||||||
stringBuffer.append(IpUtils.getIpAddr()).append("-");
|
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();
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
Method method = signature.getMethod();
|
Method method = signature.getMethod();
|
||||||
|
Loading…
Reference in New Issue
Block a user