实现思路
该拦截器通过获取访问者主机IP
地址及访问接口,放入map集合中,实现同一接口、同一IP短时间内调用次数限制
源码
拦截器类
该拦截器在调用接口之前执行
IpUtil是我自己写的一个工具类cntool
中的获取IP方法,关于这个工具类看👉这儿
ExpiringMap
是一个可以设置时效的Map集合,.expiration(3, TimeUnit.SECONDS)
参数第一个是生效时间,这个生效时间是以秒来计的,比如说你想让存的键值生效时间为1分钟
,那就在第一个参数的位置写上60
,5分钟
的话就写上300
,以此类推
package com.zygh.nodemanage.component;
import com.cntool.core.ip.IpUtil;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @program: nodeoffice
* @description: 重复提交接口拦截
* @author: ID-Tang
* @create: 2022-03-04 10:57
**/
@Component
public class RepeatHandler implements HandlerInterceptor {
private ExpiringMap<String, String> timeMap = ExpiringMap.builder()
// 设置每个key有效时间3s, 如果key不设置过期时间,key永久有效
.expiration(3, TimeUnit.SECONDS)
// 允许更新过期时间值
.variableExpiration()
// CREATED: 只在put和replace方法重置过期时间
.expirationPolicy(ExpirationPolicy.CREATED).build();
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*
* @return true继续执行 false中断执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
try {
//获取用户访问地址
String requestUrl = request.getRequestURI();
System.out.println(requestUrl);
String ipAddr = IpUtil.getIpAddr(request);
if (requestUrl.equals(timeMap.get(ipAddr))) {
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().print("{\"code\":403,\"message\":\"手速太快,注意鼠标身体呦~\"}");
response.getWriter().flush();
return false;
}
timeMap.put(ipAddr, requestUrl);
System.out.println(timeMap.size());
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
webConfig
在
addInterceptors
方法中,addPathPatterns
为设置拦截路径/**
为拦截所有接口,excludePathPatterns
为放行路径,像list
、query
这类查询的接口,我们一般没必要做多次访问的拦截机制,所以在代码中我选择了放行
package com.zygh.nodemanage.config;
import com.zygh.nodemanage.component.RepeatHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import javax.annotation.Resource;
/**
* 开放路径
*
* @author admin
*/
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册Interceptor拦截器
registry.addInterceptor(repeatHandler)
.addPathPatterns("/**")
.excludePathPatterns("/**/get*")
.excludePathPatterns("/**/list*")
.excludePathPatterns("/**/*List")
.excludePathPatterns("/**/query*");
}
}
到这里就大功告成了👍