Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
finance-manage
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
finance-oa
finance-manage
Commits
5c155f5f
Commit
5c155f5f
authored
Aug 17, 2021
by
RuoYi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
支持自定义注解实现接口限流
parent
03cf98d3
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
225 additions
and
15 deletions
+225
-15
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
...mon/src/main/java/com/ruoyi/common/annotation/Excels.java
+1
-1
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
...rc/main/java/com/ruoyi/common/annotation/RateLimiter.java
+40
-0
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
...on/src/main/java/com/ruoyi/common/constant/Constants.java
+5
-0
ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
...ommon/src/main/java/com/ruoyi/common/enums/LimitType.java
+20
-0
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
...n/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
+116
-0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
...src/main/java/com/ruoyi/framework/config/RedisConfig.java
+29
-0
ruoyi-ui/src/utils/request.js
ruoyi-ui/src/utils/request.js
+3
-3
ruoyi-ui/src/utils/ruoyi.js
ruoyi-ui/src/utils/ruoyi.js
+11
-11
No files found.
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
View file @
5c155f5f
...
...
@@ -14,5 +14,5 @@ import java.lang.annotation.Target;
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Excels
{
Excel
[]
value
();
public
Excel
[]
value
();
}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
0 → 100644
View file @
5c155f5f
package
com.ruoyi.common.annotation
;
import
java.lang.annotation.Documented
;
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.Constants
;
import
com.ruoyi.common.enums.LimitType
;
/**
* 限流注解
*
* @author ruoyi
*/
@Target
(
ElementType
.
METHOD
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Documented
public
@interface
RateLimiter
{
/**
* 限流key
*/
public
String
key
()
default
Constants
.
RATE_LIMIT_KEY
;
/**
* 限流时间,单位秒
*/
public
int
time
()
default
60
;
/**
* 限流次数
*/
public
int
count
()
default
100
;
/**
* 限流类型
*/
public
LimitType
limitType
()
default
LimitType
.
DEFAULT
;
}
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
View file @
5c155f5f
...
...
@@ -74,6 +74,11 @@ public class Constants
*/
public
static
final
String
REPEAT_SUBMIT_KEY
=
"repeat_submit:"
;
/**
* 限流 redis key
*/
public
static
final
String
RATE_LIMIT_KEY
=
"rate_limit:"
;
/**
* 验证码有效期(分钟)
*/
...
...
ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
0 → 100644
View file @
5c155f5f
package
com.ruoyi.common.enums
;
/**
* 限流类型
*
* @author ruoyi
*/
public
enum
LimitType
{
/**
* 默认策略全局限流
*/
DEFAULT
,
/**
* 根据请求者IP进行限流
*/
IP
}
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
0 → 100644
View file @
5c155f5f
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.Signature
;
import
org.aspectj.lang.annotation.Aspect
;
import
org.aspectj.lang.annotation.Before
;
import
org.aspectj.lang.annotation.Pointcut
;
import
org.aspectj.lang.reflect.MethodSignature
;
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.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.ServletUtils
;
import
com.ruoyi.common.utils.StringUtils
;
import
com.ruoyi.common.utils.ip.IpUtils
;
/**
* 限流处理
*
* @author ruoyi
*/
@Aspect
@Component
public
class
RateLimiterAspect
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
RateLimiterAspect
.
class
);
private
RedisTemplate
<
Object
,
Object
>
redisTemplate
;
private
RedisScript
<
Long
>
limitScript
;
@Autowired
public
void
setRedisTemplate1
(
RedisTemplate
<
Object
,
Object
>
redisTemplate
)
{
this
.
redisTemplate
=
redisTemplate
;
}
@Autowired
public
void
setLimitScript
(
RedisScript
<
Long
>
limitScript
)
{
this
.
limitScript
=
limitScript
;
}
// 配置织入点
@Pointcut
(
"@annotation(com.ruoyi.common.annotation.RateLimiter)"
)
public
void
rateLimiterPointCut
()
{
}
@Before
(
"rateLimiterPointCut()"
)
public
void
doBefore
(
JoinPoint
point
)
throws
Throwable
{
RateLimiter
rateLimiter
=
getAnnotationRateLimiter
(
point
);
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
(
StringUtils
.
isNull
(
number
)
||
number
.
intValue
()
>
count
)
{
throw
new
ServiceException
(
"访问过于频繁,请稍后再试"
);
}
log
.
info
(
"限制请求'{}',当前请求'{}',缓存key'{}'"
,
count
,
number
.
intValue
(),
key
);
}
catch
(
ServiceException
e
)
{
throw
e
;
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"服务器限流异常,请稍后再试"
);
}
}
/**
* 是否存在注解,如果存在就获取
*/
private
RateLimiter
getAnnotationRateLimiter
(
JoinPoint
joinPoint
)
{
Signature
signature
=
joinPoint
.
getSignature
();
MethodSignature
methodSignature
=
(
MethodSignature
)
signature
;
Method
method
=
methodSignature
.
getMethod
();
if
(
method
!=
null
)
{
return
method
.
getAnnotation
(
RateLimiter
.
class
);
}
return
null
;
}
public
String
getCombineKey
(
RateLimiter
rateLimiter
,
JoinPoint
point
)
{
StringBuffer
stringBuffer
=
new
StringBuffer
(
rateLimiter
.
key
());
if
(
rateLimiter
.
limitType
()
==
LimitType
.
IP
)
{
stringBuffer
.
append
(
IpUtils
.
getIpAddr
(
ServletUtils
.
getRequest
()));
}
MethodSignature
signature
=
(
MethodSignature
)
point
.
getSignature
();
Method
method
=
signature
.
getMethod
();
Class
<?>
targetClass
=
method
.
getDeclaringClass
();
stringBuffer
.
append
(
"-"
).
append
(
targetClass
.
getName
()).
append
(
"- "
).
append
(
method
.
getName
());
return
stringBuffer
.
toString
();
}
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
View file @
5c155f5f
...
...
@@ -6,6 +6,7 @@ import org.springframework.context.annotation.Bean;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.redis.connection.RedisConnectionFactory
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.script.DefaultRedisScript
;
import
org.springframework.data.redis.serializer.StringRedisSerializer
;
import
com.fasterxml.jackson.annotation.JsonAutoDetect
;
import
com.fasterxml.jackson.annotation.JsonTypeInfo
;
...
...
@@ -47,4 +48,32 @@ public class RedisConfig extends CachingConfigurerSupport
template
.
afterPropertiesSet
();
return
template
;
}
@Bean
public
DefaultRedisScript
<
Long
>
limitScript
()
{
DefaultRedisScript
<
Long
>
redisScript
=
new
DefaultRedisScript
<>();
redisScript
.
setScriptText
(
limitScriptText
());
redisScript
.
setResultType
(
Long
.
class
);
return
redisScript
;
}
/**
* 限流脚本
*/
private
String
limitScriptText
()
{
return
"local key = KEYS[1]\n"
+
"local count = tonumber(ARGV[1])\n"
+
"local time = tonumber(ARGV[2])\n"
+
"local current = redis.call('get', key);\n"
+
"if current and tonumber(current) > count then\n"
+
" return current;\n"
+
"end\n"
+
"current = redis.call('incr', key)\n"
+
"if tonumber(current) == 1 then\n"
+
" redis.call('expire', key, time)\n"
+
"end\n"
+
"return current;"
;
}
}
ruoyi-ui/src/utils/request.js
View file @
5c155f5f
...
...
@@ -29,9 +29,9 @@ service.interceptors.request.use(config => {
if
(
typeof
value
===
'
object
'
)
{
for
(
const
key
of
Object
.
keys
(
value
))
{
if
(
value
[
key
]
!==
null
&&
typeof
(
value
[
key
])
!==
'
undefined
'
)
{
let
params
=
propName
+
'
[
'
+
key
+
'
]
'
let
subPart
=
encodeURIComponent
(
params
)
+
'
=
'
url
+=
subPart
+
encodeURIComponent
(
value
[
key
])
+
'
&
'
let
params
=
propName
+
'
[
'
+
key
+
'
]
'
;
let
subPart
=
encodeURIComponent
(
params
)
+
'
=
'
;
url
+=
subPart
+
encodeURIComponent
(
value
[
key
])
+
'
&
'
;
}
}
}
else
{
...
...
ruoyi-ui/src/utils/ruoyi.js
View file @
5c155f5f
...
...
@@ -55,17 +55,17 @@ export function resetForm(refName) {
// 添加日期范围
export
function
addDateRange
(
params
,
dateRange
,
propName
)
{
let
search
=
params
search
.
params
=
typeof
(
search
.
params
)
===
'
object
'
&&
search
.
params
!==
null
&&
!
Array
.
isArray
(
search
.
params
)
?
search
.
params
:
{}
dateRange
=
Array
.
isArray
(
dateRange
)
?
dateRange
:
[]
if
(
typeof
(
propName
)
===
'
undefined
'
)
{
search
.
params
[
'
beginTime
'
]
=
dateRange
[
0
]
search
.
params
[
'
endTime
'
]
=
dateRange
[
1
]
}
else
{
search
.
params
[
'
begin
'
+
propName
]
=
dateRange
[
0
]
search
.
params
[
'
end
'
+
propName
]
=
dateRange
[
1
]
}
return
search
let
search
=
params
;
search
.
params
=
typeof
(
search
.
params
)
===
'
object
'
&&
search
.
params
!==
null
&&
!
Array
.
isArray
(
search
.
params
)
?
search
.
params
:
{};
dateRange
=
Array
.
isArray
(
dateRange
)
?
dateRange
:
[];
if
(
typeof
(
propName
)
===
'
undefined
'
)
{
search
.
params
[
'
beginTime
'
]
=
dateRange
[
0
];
search
.
params
[
'
endTime
'
]
=
dateRange
[
1
];
}
else
{
search
.
params
[
'
begin
'
+
propName
]
=
dateRange
[
0
];
search
.
params
[
'
end
'
+
propName
]
=
dateRange
[
1
];
}
return
search
;
}
// 回显数据字典
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment