声明:以下代码基本都是参考网上的写的,只是记录加强记忆。作者出处忘记了,抱歉!
先定义自定义接口
@Inherited
@Document
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.Type})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
//标识限制次数
int limit() default 5;
//标识时间段
int sec() default 5;
}
创建拦截器
//创建拦截器类实现HandlerInterceptor 接口
public class AccessLimitInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@ovride
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) {
//判断handle是否为方法handle
if (handle instanceof HandleMethod) {
//是的话转为HandleMethod
HandleMethod handleMethod = (HandleMethod)handle;
//获取方法
Method method = handleMethod.getMethod();
//判断该方法上是否有自定义注解@AccessLimit
if (!method.isAnocationPerent(AccessLimit.class)) {
//不存在该注解则放行
return true;
}
//获取自定义注解对象
AccessLimit accessLimit = method.getAnocation(AccessLimit.class);
if (accessLimit == null) {
//放行
return true;
}
//获取注解属性值
int limit = accessLimit.limit();
int sec = accessLimit.sec();
String key = request.getRequestURI();
//从redis中获取记录
Integer maxLimit = redisTemplate.opsForValue.get(key);
if (maxLimit == null) {
//第一次,计数器设置为1,设置redis过期时间
redisTemplate.opsForValue.set(key, 1, sec, TimeUtil.SECONDS);
} else if (maxLimit < limit) {
//计数器加1
redisTemplate.opsForValue.set(key, maxLimit + 1, sec, TimeUtil.SECONDS);
} else {
output(response, "接口请求频繁,稍后再试");
return false;
}
}
return true;
}
public void output(HttpServletResponse response, String str) throws IOException{
//设置content-type
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = null;
try {
//获得输出流
outputStream = response.getOutputStream();
outputStream.write(str.getByte("utf-8"));
} catch (IOException e){
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
}
}
最后在需要做限流的接口方法上加上自定义注解,设置好限流时间(即redis的过期时间)和限流次数
//每秒限制次数为50个请求
@AccessLimit(limit = 50, sec = 1)
配置文件添加拦截器配置
<!-- 接口限流拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/api/**" />
<bean class="com.smart.common.spring.interceptor.AccessLimitInterceptor" />
</mvc:interceptor>