一、自定义注解
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** * @author Yang * @version 1.0 * @date 2021/2/22 10:28 */@Retention(RUNTIME)@Target(METHOD)public @interface AccessLimit {int seconds();
int maxCount();
boolean needLogin() default true;
}
二、定义拦截器
import com.alibaba.fastjson.JSON;
import com.mengxiangnongfu.payment.annotation.AccessLimit;
import com.mengxiangnongfu.payment.commons.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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;
/** * @author Yang * @version 1.0 * @date 2021/2/22 10:29 */@Componentpublic class FangshuaInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate RedisUtil redisUtil;
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断请求是否属于方法的请求if (handler instanceof HandlerMethod) {HandlerMethod hm = (HandlerMethod) handler;
//获取方法中的注解,看是否有该注解AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (accessLimit == null) {return true;
}int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
boolean login = accessLimit.needLogin();
String key = "1";
//如果需要登录if (login) {//获取登录的session进行判断//.....key += "" + "1";
//这里假设用户是1,项目中是动态获取的userId}//从redis中获取用户访问的次数Integer count = (Integer) redisUtil.get(key);
if (count == null) {//第一次访问redisUtil.set(key, 1, seconds);
} else if (count < maxCount) {//加1redisUtil.incr(key, 1);
} else {//超出访问次数render(response, "请求过于频繁~请稍后再试~");
//这里的CodeMsg是一个返回参数return false;
}}return true;
}private void render(HttpServletResponse response, String cm) throws Exception {response.setContentType("application/json;
charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(cm);
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}}
三、Redis工具类
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/** * @author Yang * @version 1.0 * @date 2020/11/29 17:06 */@Component@Slf4jpublic class RedisUtil {@AutowiredRedisTemplate redisTemplate;
// =============================common============================/*** 指定缓存失效时间** @param key键* @param time 时间(秒)* @return*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);
}return true;
} catch (Exception e) {log.error(key, e);
return false;
}}/*** 根据key 获取过期时间** @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}/*** 判断key是否存在** @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);
} catch (Exception e) {log.error(key, e);
return false;
}}/*** 删除缓存** @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);
} else {redisTemplate.delete(CollectionUtils.arrayToList(key));
}}}// ============================String=============================/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);
}/*** 普通缓存放入** @param key键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {log.error(key, e);
return false;
}}/*** 普通缓存放入并设置时间** @param key键* @param value 值* @param time时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {set(key, value);
}return true;
} catch (Exception e) {log.error(key, e);
return false;
}}/*** 递增 适用场景: https://blog.csdn.net/y_y_y_k_k_k_k/article/details/79218254 高并发生成订单号,秒杀类的业务逻辑等。。** @param key键* @param delta 要增加几(大于0)* @return*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");
}return redisTemplate.opsForValue().increment(key, delta);
}/*** 递减** @param key键* @param delta 要减少几(小于0)* @return*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");
}return redisTemplate.opsForValue().increment(key, -delta);
}// ================================Map=================================/*** HashGet** @param key键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);
}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public Map
四、POM文件
org.springframework.bootspring-boot-starter-aoporg.springframework.bootspring-boot-starter-data-redis
记得配置redis的连接
在需要拦截的地方加入注解即可@AccessLimit(seconds = 5, maxCount = 1, needLogin = false) seconds重置访问频率时间 maxCount 最多请求次数
【SpringBoot项目中接口防刷的完整代码】到此这篇关于SpringBoot项目中接口防刷的完整代码的文章就介绍到这了,更多相关SpringBoot接口防刷内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读