对接口访问次数的限制 是从java版web项目公众号中看到 于是百度结合自己现有项目写了一下
首先需要定义一个注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Auther: lirui
* @Date: 2020/11/1 0:12
* @Description: 接口防刷注解类
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
int seconds();
int maxcount();
boolean needLogin() default true;
}
接口防刷拦截器
import com.bigdata.bigdata.annotations.AccessLimit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
/**
* @Auther: lirui
* @Date: 2020/11/1 0:12
* @Description: 接口防刷拦截器
*/
@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断请求是否属于方法的请求
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod=(HandlerMethod) handler;
//获取方法中的注解,看是否有该注解
AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
if(accessLimit==null){
return true;
}
int seconds = accessLimit.seconds();
int maxcount = accessLimit.maxcount();
boolean login = accessLimit.needLogin();
String key = request.getRequestURI();
//如果需要登录
if(login){
//获取登录的session进行判断
//.......
key+=""+"1"; //用户id userId
}
//从redis中获取用户访问的次数
// AccessKey ak = AccessKey.withExpire(seconds);
Integer count= (Integer)redisTemplate.opsForValue().get(key);
if(count==null){
//第一次访问
redisTemplate.opsForValue().set(key,1);
}else if(count<maxcount){
//加1
redisTemplate.opsForValue().set(key,(Integer)redisTemplate.opsForValue().get(key)+1);
}else{
//超出访问次数
render(response,key+"接口请求次数过多!");
return false;
}
}
return true;
}
private void render(HttpServletResponse response, String message)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(message.getBytes("UTF-8"));
out.flush();
out.close();
}
}
将拦截器注册到spring容器中
package com.bigdata.bigdata.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @Auther: lirui
* @Date: 2020/11/1 0:12
* @Description: 将防刷拦截器注册 到springcloud容器中
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private FangshuaInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
controller接口编写
import com.bigdata.bigdata.annotations.AccessLimit;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Auther: lirui
* @Date: 2020/11/1 0:12
* @Description: 防刷接口测试
*/
@RestController
@RequestMapping("/fangshua")
public class FangshuaController {
@AccessLimit(seconds = 5, maxcount = 5, needLogin = false)
@RequestMapping("/test")
public String test() {
return "请求成功";
}
}