Redis 中的 setnx 命令_redis setnx-CSDN博客
-------------------------------------------------------------------------------------------------------------------------------
下面直接上最基础的代码
后面可以在此基础上优化
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ForbidRepeatClick { }
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Component
@Aspect
@Order(1)
public class ForbidRepeatClickInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(ForbidRepeatClickInterceptor.class);
@Autowired
private RedisTemplate redisTemplate;
@Pointcut("@annotation(ForbidRepeatClick)")
public void pointcut() {
}
@Around("pointcut()")
public Object forbidRepeatClick(ProceedingJoinPoint pjp) throws Throwable {
System.out.println(333);
//1、根据入参方法名获取组装的redis的key值
String redisKey = getRedisKey(pjp);
LOGGER.info("方法的参数为:{}", redisKey);
//情景是,点击一次,违约成本反欺诈就开始分析,按钮就不能点击了.然后完成分析后, 后端return给前端成功,前端跳转页面.
//这样写是3秒内无法重复点击此提交按钮,
//去掉过期时间,加上2.1的delete就是当这个方法走完后,按钮才能被点击
if (redisTemplate.opsForValue().setIfAbsent(redisKey, "exist",10,TimeUnit.SECONDS)) {
//假设 lockName 是你的锁的名称,expireTime 是你希望锁持续的时间(以分钟为单位)
redisTemplate.expire(redisKey, 10, TimeUnit.SECONDS);
Object res = null;
System.out.println(444);
//2、当前方法同一时间段无完全同参数调用,则继续往下执行
res = pjp.proceed();
System.out.println(555);
//2.1 执行后将数据从redis删除 (建议设置过期时间,自动删除)
redisTemplate.delete("aaa");
System.out.println(666);
return res;
}
//3、当前方法同一时间段具有相同参数执行,则不再执行,直接返回错误标识
LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:exist");
return "不要重复点击按钮";
}
/**
* 获取存储的redis的key值
*
* @param pjp
* @return
*/
private String getRedisKey(ProceedingJoinPoint pjp) throws InstantiationException, IllegalAccessException {
//1.获取参数值
Object[] args = pjp.getArgs();
//2.获取参数名称
Signature signature = pjp.getSignature();
if (signature instanceof MethodSignature) {
MethodSignature methodSignature = (MethodSignature) signature;
String[] parameterNames = methodSignature.getParameterNames();
}
//3.获取返回类型
Signature signature1 = pjp.getSignature();
if (signature1 instanceof MethodSignature) {
MethodSignature methodSignature = (MethodSignature) signature;
// 被切的方法
Method method = methodSignature.getMethod();
// 返回类型
Class<?> methodReturnType = method.getReturnType();
// 实例化
Object o = methodReturnType.newInstance();
}
//4.全限定类名
Signature signature2 = pjp.getSignature();
String declaringTypeName = signature2.getDeclaringTypeName();
//5.方法名
Signature signature3 = pjp.getSignature();
String name = signature3.getName();
// 1、获取被代理的对象类型
String className = pjp.getTarget().getClass().getName();
// 2、获取当前代理的方法名
String methodName = pjp.getSignature().getName();
// 3、获取入参并转换成jason串 入参要有userId,或者公共方法获取userId
String convertJson = convertArgsToJson(pjp.getArgs());
//(此key值过长,建议用md5加密转换缩短长度)
String redisKey = className + "->" + methodName + "->" + convertJson;
return redisKey;
}
/**
* 将传入的参数拼接成json类型的字符串
*
* @param args
* @return
*/
private String convertArgsToJson(Object[] args) {
StringBuilder convertJson = new StringBuilder();
for (Object object : args) {
if (!(object instanceof HttpServletRequest)) { // 此处判断不能舍去
convertJson.append(JSONObject.toJSONString(object));
}
}
return convertJson.toString();
}
}