解决的问题
限制一定时间段内访问的次数,亦可对其优化对爬虫进行有效干预
实现思路
定义拦截器对请求进行拦截验证,每请求一次次数自增1,达到这段时间内最大限制则拒绝请求。我们可以在拦截器中实现统一的时间和次数限制;也可通过配置达到灵活使用的目的,我们这里通过注解的方式实现第二种
定义注解
package com.reaps.common.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
//多少秒
int second() default 1;
//最大限制次数
int maxCount() default 1;
//是否已登录
boolean logined() default true;
}
second秒内可访问的maxCount最大次数,logined判断是否需要登录,由于这里是应用到管理系统,请求都是需要登录的,也可设置不需要登录。
定义拦截器
package com.reaps.config.web;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.reaps.common.annotations.RequestLimit;
import com.reaps.config.dao.redis.CacheService;
import com.reaps.modules.sys.utils.ShiroUtils;
public class RequestLimitInterceptor implements HandlerInterceptor{
@Autowired
private CacheService cacheService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if(handler instanceof HandlerMethod) {
HandlerMethod handlerMethod=(HandlerMethod) handler;
RequestLimit requestLimit=handlerMethod.getMethodAnnotation(RequestLimit.class);
//无注解则不需要验证,直接返回不做处理
if(requestLimit==null) {
return true;
}
//判断用户是否已经登录
if(requestLimit.logined()) {
if(!ShiroUtils.isLogin()) {
returnResponse(response, "未登录");
return false;
}
}
String key=RequestContextHolder.getRequestAttributes().getSessionId()+"_"+request.getRequestURL();
Integer count=Integer.parseInt(cacheService.get(key));
if(count==0) {
//初始化次数
cacheService.set(key, "1",requestLimit.second());
}else if(count<requestLimit.maxCount()) {
//自增1
cacheService.incr(key);
}else {
returnResponse(response, "次数超限");
return false;
}
return true;
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
private boolean returnResponse(HttpServletResponse response,String res) throws Exception{
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null ;
try{;
out = response.getWriter();
out.append(res);
return false;
}catch (Exception e){
e.printStackTrace();
response.sendError(500);
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
实现HandlerInterceptor接口对立面的方法进行具体的实现,在preHandle方法里获取注解,如果有注解对其设置的参数和缓存内的数据进行判断。
注册拦截器
package com.reaps.config.web;
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;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestLimitInterceptor requestLimitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestLimitInterceptor);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
将拦截器注册到WebMvcConfigurer
简单应用
@RequestMapping(path="checkPreAuthCode")
@ResponseBody
@RequestLimit(second=1,maxCount=1)
public boolean checkPreAuthCode(String oldValue,String preAuthCode) {
return iZyPreAuthService.checkPreAuthCode(oldValue,preAuthCode);
}
在方法上加上注解,设置参数就可以试用啦!