为了防止重复提交请求造成的问题,这里我们使用aop加上redis缓存做一个拦截器。为了方便使用,我们以注解的形式来使用。
一、新建一个自定义注解
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UrlInterceptFlag {
long millisecond() default 1000;
}
上面的注解只有一个参数,就是设置过期时间,同一个url在设置时间内只会被调用一次。防止重复操作。然后我们利用spring aop对使用了UrlInterceptFlag注解的方法进行拦截,是用redis进行缓存我们的@RequestMapping的value,缓存时间就是我们的注解时间。来看具体的代码:
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.PostConstruct;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
@Aspect
@Order(-1)
@Component
public class UrlInterceptHandleAspect {
private Logger logger = LoggerFactory.getLogger(UrlInterceptHandleAspect.class);
private final static String CACHE_PREFIX = "AOP:STUDY:";
@Autowired
private RedisClient redisClient;
@PostConstruct
public void init() {
logger.info("Url拦截切面初始化");
}
@Around(value = "@annotation(com.datatrees.loan.clearing.controller.UrlIntercept.UrlInterceptFlag)")
public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
Object obj = null;
RequestMapping classRequestMapping = pjp.getTarget().getClass().getAnnotation(RequestMapping.class);
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
UrlInterceptFlag urlInterceptFlag = method.getAnnotation(UrlInterceptFlag.class);
RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
String classKeys[] = classRequestMapping.value();
String methodKeys[] = methodRequestMapping.value();
if (methodKeys.length > 0) {
String classKey = "";
if (classKeys.length > 0) {
classKey = classKeys[0];
}
if (redisClient.setIfAbsent(CACHE_PREFIX + classKey + methodKeys[0], 1, urlInterceptFlag.millisecond())) {
logger.info("method={},value={}", method.getName(), methodKeys[0]);
obj = pjp.proceed();
} else {
obj = method.getReturnType().getConstructor().newInstance();
logger.info("method={},value={}频繁操作,请稍后再试", method.getName(), methodKeys[0]);
}
}
return obj;
}
通过上面的方法,使用了urlInterceptFlag注解的方法都会被我们的切面拦截到,然后请求路径(类和方法上的RequestMapping注解的value)通过我们的规则组装成key去redis查询,如果key存在(缓存还没过期)我们就返回一个新的实例,如果不存在,我们就可以继续操作。