wang.ramboll.extend.request.limit.interceptor.RequestFrequencyLimitInterceptor Maven / Gradle / Ivy
package wang.ramboll.extend.request.limit.interceptor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import wang.ramboll.extend.basic.util.HttpServletUtils;
import wang.ramboll.extend.basic.util.JsonUtils;
import wang.ramboll.extend.basic.util.MD5Utils;
import wang.ramboll.extend.request.limit.annotation.RequestFrequencyLimit;
import wang.ramboll.extend.request.limit.enums.RequestFrequencyLimitMode;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.Charset;
/**
* 访问请求频率限制拦截器
* @author WangRuibo
*/
public class RequestFrequencyLimitInterceptor implements HandlerInterceptor {
private RequestFrequencyLimitWork requestFrequencyLimitWork;//访问频率限制实现
private Object limitReturnObj ;//拦截时,返回的数据模型
private static final String LIMIT_MARK = "RAMBOLL.LIMIT_MARK";//拦截标记,用于在RequestAttributes中传递,方便取消拦截处理
private static final String LIMIT_MARK_MAX_TIMES = "RAMBOLL.LIMIT_MARK_MAX_TIMES";//拦截标记中最大请求次数,用于在RequestAttributes中传递,方便取消拦截处理
/**
* 访问请求频率限制拦截器 构造器
* @param requestFrequencyLimitWork 访问频率限制实现
* @param limitReturnObj 拦截时,返回的数据模型
*/
public RequestFrequencyLimitInterceptor(RequestFrequencyLimitWork requestFrequencyLimitWork, Object limitReturnObj) {
this.requestFrequencyLimitWork = requestFrequencyLimitWork;
this.limitReturnObj = limitReturnObj;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Method method = ((HandlerMethod)handler).getMethod();
//找到防刷拦截标记注解
RequestFrequencyLimit rfl = null;
if(method.isAnnotationPresent(RequestFrequencyLimit.class)){
rfl = method.getAnnotation(RequestFrequencyLimit.class);
} else {
Class cls = method.getDeclaringClass();
if(cls.isAnnotationPresent(RequestFrequencyLimit.class)){
rfl = (RequestFrequencyLimit)cls.getAnnotation(RequestFrequencyLimit.class);
}
}
if(rfl!=null){//如果有该注解
RequestFrequencyLimitMode[] mods = rfl.limitMode();//获得配置的拦截模式
StringBuilder source = new StringBuilder();//用于生成唯一请求标识的字符串
if(RequestFrequencyLimitMode.contains(RequestFrequencyLimitMode.URI,mods)){//URI模式,请求URI参与生成请求标识
source.append(request.getRequestURI()).append("|");
}
boolean isRequestBodyMode = RequestFrequencyLimitMode.contains(RequestFrequencyLimitMode.REQUEST_BODY,mods);//REQUEST_BODY模式
boolean isRequestParamMode = RequestFrequencyLimitMode.contains(RequestFrequencyLimitMode.REQUEST_PARAM,mods);//REQUEST_PARAM模式
boolean isRequestHeaderMode = RequestFrequencyLimitMode.contains(RequestFrequencyLimitMode.REQUEST_HEADER,mods);//REQUEST_HEADER模式
boolean isRequestAttributeMode = RequestFrequencyLimitMode.contains(RequestFrequencyLimitMode.REQUEST_ATTRIBUTE,mods);//REQUEST_ATTRIBUTE模式
boolean methodParamMode = isRequestBodyMode||isRequestParamMode||isRequestHeaderMode||isRequestAttributeMode;//如果是注解参数模式
if(methodParamMode){
Parameter[] parameters = method.getParameters();
for(Parameter parameter : parameters){
if(isRequestBodyMode){//带有@RequestBody注解的参数,转换为Json参与生成请求标识
RequestBody requestParam = parameter.getAnnotation(RequestBody.class);
if(requestParam!=null){
String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName("UTF-8"));
String data = JsonUtils.parseObjectToJson(JsonUtils.parseJsonToObject(body,parameter.getType(),true),true);
source.append(data).append("|");
}
}
if(isRequestParamMode){//带有@RequestParam注解的参数,参与生成请求标识
RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
if(requestParam!=null){
String paramName = requestParam.name();
if(StringUtils.isBlank(paramName)){
paramName = parameter.getName();
}
source.append("P.").append(paramName).append("=").append(JsonUtils.parseObjectToJson(request.getParameter(paramName),true)).append("|");
}
}
if(isRequestHeaderMode){//带有@RequestHeader注解的参数,参与生成请求标识
RequestHeader requestHeader = parameter.getAnnotation(RequestHeader.class);
if(requestHeader!=null){
String headerName = requestHeader.name();
if(StringUtils.isBlank(headerName)){
headerName = parameter.getName();
}
source.append("H.").append(headerName).append(":").append(JsonUtils.parseObjectToJson(request.getHeader(headerName),true)).append("|");
}
}
if(isRequestAttributeMode){//带有@RequestAttribute注解的参数,参与生成请求标识
RequestAttribute requestAttribute = parameter.getAnnotation(RequestAttribute.class);
if(requestAttribute!=null){
String attributeName = requestAttribute.name();
if(StringUtils.isBlank(attributeName)){
attributeName = parameter.getName();
}
source.append("A.").append(attributeName).append("=").append(JsonUtils.parseObjectToJson(request.getAttribute(attributeName),true)).append("|");
}
}
}
}
String md5 = MD5Utils.MD5Encode(source.toString());//用MD5生成唯一请求标识
boolean isOk = requestFrequencyLimitWork.work(md5,rfl.delay(),rfl.maxTimes());//调用处理方法确定是否需要拦截
request.setAttribute(LIMIT_MARK,md5);//向后方传递标记
request.setAttribute(LIMIT_MARK_MAX_TIMES,rfl.maxTimes());//向后方传递标记
if(!isOk){//若拦截,返回默认拦截返回对象,Json格式
HttpServletUtils.doReturnResponseJsonObject(limitReturnObj,response);
}
return isOk;
} else {
return true ;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
String limitMark = (String) request.getAttribute(LIMIT_MARK);
if(StringUtils.isNotBlank(limitMark)){
requestFrequencyLimitWork.cancelLimit(limitMark,(Long) request.getAttribute(LIMIT_MARK_MAX_TIMES));
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}