实现HandlerInterceptor接口
@Component
public class BrushProofHandler implements HandlerInterceptor {
@Autowired
RedisService redisService;
private static final String REDIS_KEY = "atm_ep::interface::ip";
@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) {
long seconds = accessLimit.seconds();
long maxCount = accessLimit.maxCount();
// 获取调用者ip
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
Integer count = (Integer) redisService.get(REDIS_KEY + ip);
if (count == null) {
redisService.set(REDIS_KEY + ip, 1, seconds);
} else if (count < maxCount) {
// 在时间允许范围内
redisService.incr(REDIS_KEY + ip, 1);
}else {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
Result message = Result.error().message("不可频繁调用!");
response.getWriter().write(JSONObject.toJSONString(message.toJSON()));
return false;
}
}
}
return true;
}
实现WebMvcConfigurer
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private BrushProofHandler brushProofHandler;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(brushProofHandler);
}
}
自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AccessLimit {
/**
* 秒
*/
long seconds() default 60;
/**
* 最大次数
*/
long maxCount() default 10;
}
使用的时候,只需将注解放在具体接口上即可,若是分布式部署,在handle中加入分布式锁即可