代码借鉴的别人的,自己做过部分修改
1. 新建文件夹并新建文件\jeecg-boot-base\jeecg-boot-base-core\src\main\java\org\jeecg\common\accesslimit\
RequestLimit.java
package org.jeecg.common.accesslimit;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
/**
* @author wangdeqiu
* @date 2018年11月2日 下午2:19:05
* 类说明:自定义注解限制访问时间长度最多访问次数
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
/**
* 允许访问的最大次数
*/
int count() default Integer.MAX_VALUE;
/**
* 时间段,单位为毫秒,默认值一分钟
*/
long time() default 60000;
}
RequestLimitContract.java
package org.jeecg.common.accesslimit;
/**
* @Author: wcb
* @Date: 2020/7/8 0008 17:05
* @Title: RequestLimitContract
* @Version 1.0
*/
//import com.suoeryun.website.utils.RedisUtil;
//import com.suoeryun.website.utils.oConvertUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class RequestLimitContract {
private static final Logger logger = LoggerFactory.getLogger(RequestLimitContract.class);
@Autowired
private RedisUtil redis;
private ScheduledExecutorService executorService2;
public RequestLimitContract() {
executorService2 = new ScheduledThreadPoolExecutor(8,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
}
@Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)")
public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException {
try {
Object[] args = joinPoint.getArgs();
HttpServletRequest request = null;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof HttpServletRequest) {
request = (HttpServletRequest) args[i];
break;
}
}
if (request == null) {
throw new RequestLimitException("方法中缺失HttpServletRequest参数");
}
// 如果不限定ip,则设定ip为本机ip
// String ip = request.getLocalAddr();
// 如果限定ip,则设定ip为客户端的ip
String ip = request.getRemoteAddr();
String url = request.getRequestURL().toString();
System.out.println(ip);
System.out.println(url);
String key = "req_limit_".concat(url).concat(ip);
if (!redis.hasKey(key) || oConvertUtils.isEmpty(redis.get(key))) {
redis.set(key, String.valueOf(1));
} else {
Integer getValue = Integer.parseInt((String) redis.get(key)) + 1;
redis.set(key, String.valueOf(getValue));
}
int count = Integer.parseInt((String) redis.get(key));
if (count > 0) {
//创建一个定时器
// Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
redis.del(key);
}
};
//这个定时器设定在time规定的时间之后会执行上面的remove方法,也就是说在这个时间后它可以重新访问
// timer.schedule(timerTask, limit.time());
// 利用线程池
executorService2.schedule(timerTask, limit.time() / 1000, TimeUnit.SECONDS);
}
System.out.println(count);
if (count > limit.count()) {
/*logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
throw new RequestLimitException();
String toLomitPath ="http://" + request.getServerName()+ ":" + request.getServerPort()+limitPath; //端口号
response.sendRedirect(toLomitPath);
*/
logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
throw new RequestLimitException("您的请求次数超限!");
}
} catch (RequestLimitException e) {
throw e;
} catch (Exception e) {
logger.error("警告,RequestLimit(次数限制)发生致命异常:", e);
}
}
}
RequestLimitException.java
package org.jeecg.common.accesslimit;
/**
* @author wangdeqiu
* @date 2018年11月2日 下午2:22:28
* 类说明:
*/
public class RequestLimitException extends RuntimeException{
private static final long serialVersionUID = 1555967171104727461L;
public RequestLimitException(){
super("HTTP请求超出设定的限制");
}
public RequestLimitException(String message){
super(message);
}
}
原作者的注释我没有去掉,但是原作者给出的代码无法限定每ip,只能限制访问次数。
2. jeecgboot全局添加错误形式\jeecg-boot-base\jeecg-boot-base-core\src\main\java\org\jeecg\common\exception\JeecgBootExceptionHandler.java
@ExceptionHandler(RequestLimitException.class)
public Result<?> requestLimitException(RequestLimitException e) {
log.error(e.getMessage() + "***********---------------", e);
// 返回错误信息
return Result.error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, e.getMessage());
}
调用
关键词:
@RequestLimit(count = 3)
示例:
@RequestLimit(count = 3)
@AutoLog(value = "测试频率")
@ApiOperation("测试频率(组件化版)")
@GetMapping(value = "/testlimit")
public Result<?> testlimit(
HttpServletRequest request
) {
System.out.println("测试频率!!");
return Result.OK("ans");
}
效果:结果
成功
失败
效果:每分钟限制访问次数,该限制在每分钟的0秒时刷新(不是在第一次请求时刷新)。
示例: 以3次每ip每分钟为例:欢迎分享,转载请注明来源:内存溢出
评论列表(0条)