若依框架实现后端防止用户重复点击
基于自定义注解、切面、Redis实现
1. 添加自定义注解:
代码放置位置:com/ruoyi/common/annotation/RepeatClick.java
time: 时间默认0;
unit:单位默认 秒;
key: 默认空字符串
package com.ruoyi.framework.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;/*** @author yizhi*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatClick {/*** 时间*/int time() default 0;/*** 时间单位,默认秒*/TimeUnit unit() default TimeUnit.SECONDS;/*** 默认会校验的数据*/String key() default "";
}
2. 添加自定义切面:
代码放置位置:com/ruoyi/framework/aspectj/RepeatClickAspect.java
基于注解和Redis实现防止重复点击
package com.ruoyi.framework.aspectj;import com.ruoyi.common.annotation.RepeatClick;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.extern.log4j.Log4j2;
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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;import javax.annotation.Resource;
import java.util.UUID;/*** @author yizhi*/
@Aspect
@Component
@Log4j2
public class RepeatClickAspect {@Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 方式一** @param joinPoint* @param repeatClick* @return* @throws Throwable*/@Around("@annotation(repeatClick)")public Object repeatClick(ProceedingJoinPoint joinPoint, RepeatClick repeatClick) throws Throwable {System.out.println("进入切面了");Object[] args = joinPoint.getArgs();// 重复点击注解为空 跳过if (ObjectUtils.isEmpty(repeatClick)) {return joinPoint.proceed(args);}// 使用错误提示if (ObjectUtils.isEmpty(repeatClick.key()) || repeatClick.time() == 0) {log.error("注意:存在自定义注解,使用异常:请检查是否设置key, time, unit");return joinPoint.proceed(args);}String repeatClickKey = repeatClick.key() + SecurityUtils.getLoginUser().getUserId();if (Boolean.TRUE.equals(redisTemplate.hasKey(repeatClickKey))) {return AjaxResult.error("请勿重复点击");}redisTemplate.opsForValue().set(repeatClickKey, UUID.randomUUID().toString());redisTemplate.expire(repeatClickKey, repeatClick.time(), repeatClick.unit());return joinPoint.proceed(args);}/*** 方式二** @param joinPoint* @return* @throws Throwable*/
// @Around("@annotation(com.ruoyi.framework.annotation.RepeatClick)")
// public Object repeatClick(ProceedingJoinPoint joinPoint) throws Throwable {
// System.out.println("进入切面了");
// Object[] args = joinPoint.getArgs();
// MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// RepeatClick repeatClick = signature.getMethod().getAnnotation(RepeatClick.class);
// // 重复点击注解为空 跳过
// if (ObjectUtils.isEmpty(repeatClick)) {
// return joinPoint.proceed(args);
// }
// // 使用错误提示
// if (ObjectUtils.isEmpty(repeatClick.key()) || repeatClick.time() == 0) {
// log.error("注意:存在自定义注解,使用异常:请检查是否设置key, time, unit");
// return joinPoint.proceed(args);
// }
// String repeatClickKey = repeatClick.key() + SecurityUtils.getLoginUser().getUserId();
// if (Boolean.TRUE.equals(redisTemplate.hasKey(repeatClickKey))) {
// return AjaxResult.error("请勿重复点击");
// }
// redisTemplate.opsForValue().set(repeatClickKey, UUID.randomUUID().toString());
// redisTemplate.expire(repeatClickKey, repeatClick.time(), repeatClick.unit());
// return joinPoint.proceed(args);
// }
}
3. 最后在controller中添加注解进行测试
key: 我给自己规定填写 —完整接口名称(因为唯一)
time和unit合起来一起使用,unit默认是秒,那这个就是10秒
如果unit 设置为 分钟,那这个就是十分钟
@RepeatClick(key = "bsLable.ceshi", time = 10)@RepeatClick(key = "bsLable.ceshi", time = 10, unit = TimeUnit.MINUTES)