import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 限流注解
* @see AccessLimitInterceptor
* @author
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
/**
* 时间段(秒)
* @return
*/
int seconds();
/**
* 时间段内最大请求次数
* @return
*/
int maxCount();
}
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import com.weifengqi18.commons.web.util.WebTools;
import com.dmore.exception.BizErrorException;
/**
* 限流实现
* 尽量设置短key的过期时间,减少误差
*
* @author
*/
public class AccessLimitInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod hm = (HandlerMethod) handler;
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (Objects.isNull(accessLimit)) {
return true;
}
int seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
//
String key = new StringBuffer("channelId:")
.append(WebTools.getChannelId().get())
.append("userId:")
.append(WebTools.getUserId().get())
.append("uri:")
.append(request.getServletPath())
.toString();
//第一次访问,设置key、值、过期时间
if (!redisTemplate.hasKey(key)) {
redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);
return true;
}
int count = redisTemplate.opsForValue().get(key);
// 如果访问次数<最大次数,则加1操作
if (count < maxCount) {
redisTemplate.opsForValue().increment(key);
return true;
}
//超过最大值返回操作频繁
if (count >= maxCount) {
throw new BizErrorException("服务器繁忙请稍后重试");
}
return true;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* spring mvc 配置类
*/
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ServerProperties serverProperties;
@Autowired
AccessLimitInterceptor accessLimitInterceptor;
@Bean
public AccessLimitInterceptor accessLimitInterceptor() {
return new AccessLimitInterceptor();
}
/**
* 配置拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessLimitInterceptor)
.excludePathPatterns(serverProperties.getError().getPath());
}
}
使用
@RestController
@RequestMapping(value = "/")
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@Autowired
private IUserService userService;
@RequestMapping(value = "test")
@AccessLimit(seconds = 1,maxCount = 2)
public String test(){
return "papapapap@qq.com";
}
}