Spring AOP+Annotation实现请求限制频率
使用Spring AOP+Annotation注解实现对Controller拦截,限制单ip对方法请求频率。
Annotation注解源代码
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {
int time() default 10;
int count() default 12;
int waits() default 10;
}
AOP源代码
import cn.cypcc.utils.RedisUtils;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
@Order(1)
public class RequestLimitAspect {
private static final String REQ_LIMIT = "REQ_LIMIT";
private RedisUtils redisUtils;
@Autowired
public void setRedisUtils(RedisUtils redisUtils) {
this.redisUtils = redisUtils;
}
@Around("@annotation(cn.cypcc.filter.RequestLimit)")
public Object method(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
RequestLimit limit = method.getAnnotation(RequestLimit.class);
if (limit == null) {
return pjp.proceed();
}
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
int time = limit.time();
int count = limit.count();
int waits = limit.waits();
String ip = realIP(request);
String url = request.getRequestURI();
String key = generateKey(url, ip);
int nowCount = redisUtils.get(key) == null ? 0 : Integer.parseInt(redisUtils.get(key));
if (nowCount == 0) {
nowCount++;
redisUtils.set(key, String.valueOf(nowCount), time, TimeUnit.SECONDS);
return pjp.proceed();
} else {
redisUtils.increment(key);
if (nowCount >= count) {
redisUtils.expire(key, waits, TimeUnit.SECONDS);
return returnLimit();
}
}
return pjp.proceed();
}
private static String generateKey(String url, String ip) {
StringBuilder sb = new StringBuilder();
sb.append(REQ_LIMIT);
sb.append(url);
sb.append("_");
sb.append(ip);
return sb.toString();
}
private String realIP(HttpServletRequest request) {
String xff = request.getHeader("x-forwarded-for");
if (xff != null) {
int index = xff.indexOf(',');
if (index != -1) {
xff = xff.substring(0, index);
}
return xff.trim();
} else if (request.getHeader("x-real-ip") != null) {
return request.getHeader("x-real-ip");
}
return request.getRemoteAddr();
}
private String returnLimit() throws IOException {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getResponse();
PrintWriter out = response.getWriter();
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
out.println(new JSONObject() {{
put("code", "485");
put("reason", "Access Denied");
}}.toJSONString());
out.flush();
out.close();
return null;
}
如果出现任何问题,欢迎留言,