首先寫一個注解
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 ityangshuai
*/
@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {
int seconds();
int maxCount();
boolean needLogin()default true;
}
再寫一個攔截器
import cn.sipaote.human.annotation.AccessLimit;
import cn.sipaote.human.utils.RedisUtils;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @description:
* @author: yangshuai
* @create: 2020-03-25 15:43
**/
@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisUtils redisUtils;
@Override
public 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 = request.getRequestURI();
//如果需要登錄
if(login){
//獲取登錄的session進行判斷
//.....
key+=""+"1"; //這里假設用戶是1,項目中是動態獲取的userId
}
//從redis中獲取用戶訪問的次數(redis中保存的key保存30(seconds)秒,redisUtils使用的單位是秒,意思是5秒內重復請求接口限制次數)
Integer count = redisUtils.get(key,Integer.class,seconds);
if(count == null){
//第一次訪問
redisUtils.set(key,1,5);
}else if(count < maxCount){
//加1
redisUtils.increment(key);
}else{
//超出訪問次數
render(response);
return false;
}
}
return true;
}
private void render(HttpServletResponse response)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = "{'mdg':'請求次數太多了'}";
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}
}
附上redisUtils
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ValueOperations<String, String> valueOperations;
/**
* 不設置過期時長
*/
public final static long NOT_EXPIRE = -1;
/**
* 設置key value
* @param key
* @param value
*/
public void set(String key, Object value){
set(key, value, CacheConstant.DEFAULT_EXPIRE);
}
public void set(String key, Object value, long expire){
valueOperations.set(key, toJson(value));
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
}
/**
* 根據key獲得對象
*/
public <T> T get(String key, Class<T> clazz) {
return get(key, clazz, NOT_EXPIRE);
}
public <T> T get(String key, Class<T> clazz, long expire) {
String value = valueOperations.get(key);
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value == null ? null : fromJson(value, clazz);
}
/**
* 根據key獲得value
* @param key
* @return
*/
public String get(String key) {
return get(key, NOT_EXPIRE);
}
public String get(String key, long expire) {
String value = valueOperations.get(key);
if(expire != NOT_EXPIRE){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
return value;
}
public void increment(String key) {
redisTemplate.opsForValue().increment(key,1L);
}
}
再把Interceptor注冊到springboot中
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthorityInterceptor authorizationInterceptor;
@Autowired
private FangshuaInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] excludes = new String[]{"/enterprise/static/**","/static/**"};
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**").excludePathPatterns(excludes);
registry.addInterceptor(interceptor);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowCredentials(true).maxAge(3600);
}
}
接口調用
@RestController
@RequestMapping("/bid-applicant")
public class BidApplicantController extends BaseController {
@AccessLimit(seconds=30, maxCount=5, needLogin=true)
@RequestMapping("/fangshua")
public ResponseInfo fangshua(){
return ResponseInfo.ok("請求成功");
}
測試結果
從第一次請求后的30秒超過5次請求,會報錯。