说明
用了注解的方式进行对接口防刷的功能,防止重复多次调用
注解类
package cn.yepk.cases.access.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author :yepk
* @version :1.0
* @apiNote :访问限制注解
* @date :2021-02-07-15:46
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
/**
* 秒值
**/
int seconds();
/**
* 秒值中最大访问次数
**/
int maxCount();
}
拦截器中实现
package cn.yepk.cases.access.interceptor;
import cn.yepk.cases.access.annotation.AccessLimit;
import cn.yepk.cases.access.domain.Result;
import cn.yepk.cases.access.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* @author :yepk
* @version :1.0
* @apiNote :访问控制拦截器
* @date :2021-02-07-15:48
*/
@Component
public class AccessInterceptor extends HandlerInterceptorAdapter {
@Resource
private RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断请求是否属于方法的请求
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
//获取方法中的注解,看是否有该注解
AccessLimit accessLimit = method.getMethodAnnotation(AccessLimit.class);
if (accessLimit == null) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
String key = "ACCESS:" + request.getRequestURI();
//从redis中获取用户访问的次数
Integer count = (Integer) redisUtil.getV(key);
if (count == null) {
//第一次访问 设置访问次数1 seconds秒释放
redisUtil.set(key,1, seconds);
} else if (count < maxCount) {
//加1
redisUtil.incr(key, 1);
} else {
//超出访问次数
render(response, new Result().setError("重复访问", "400"));
return false;
}
}
return true;
}
private void render(HttpServletResponse response, Result code) throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(code);
out.write(str.getBytes(StandardCharsets.UTF_8));
out.flush();
out.close();
}
}
注册拦截器
package cn.yepk.cases.access.config;
import cn.yepk.cases.access.interceptor.AccessInterceptor;
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.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.annotation.Resource;
/**
* @author :yepk
* @version :1.0
* @apiNote :web配置
* @date :2021-02-07-15:55
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private AccessInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
接口测试
package cn.yepk.cases.access.controller;
import cn.yepk.cases.access.annotation.AccessLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author :yepk
* @version :1.0
* @apiNote :测试接口
* @date :2020-11-26-10:52
*/
@RequestMapping(value = "test", produces = "application/json;charset=utf-8")
@RestController
public class TestController {
@GetMapping(value = "index")
@AccessLimit(maxCount = 5, seconds = 5)
public String test() {
return "{code:200}";
}
}
效果
后续推展
如果是限制单个用户或单个ip,redis键加上用户id或ip即可