- 引入SpringAOP
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 配置redis,并创建redis工具类
redis配置此处略过
@Service
@Slf4j
public class RedisService {
@Resource
private StringRedisTemplate stringRedisTemplate;
public boolean existKey(String key) {
log.debug("existKey().params:" + key);
return stringRedisTemplate.hasKey(key);
}
public Boolean delKey(String key) {
log.debug("delKey().params:" + key);
Boolean delete = stringRedisTemplate.delete(key);
return delete;
}
public boolean addString(String key, String value) {
BoundValueOperations<String, String> ops = stringRedisTemplate.boundValueOps(key);
try {
ops.set(value);
return true;
} catch (Exception e) {
log.error("redis添加异常." + e.getMessage(), e);
e.printStackTrace();
return false;
}
}
public boolean addString(String key, String value, long timeout, TimeUnit timeUnit) {
BoundValueOperations<String, String> ops = stringRedisTemplate.boundValueOps(key);
try {
ops.set(value, timeout, timeUnit);
return true;
} catch (Exception e) {
log.error("redis添加异常." + e.getMessage(), e);
e.printStackTrace();
return false;
}
}
}
- 创建注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FormLock {
/**
* 指定时间内不可重复提交,单位毫秒
* @return
*/
long timeout() default 3000;
}
- 创建AOP环绕通知处理类
@Slf4j
@Aspect
@Component
public class FormLockAspect {
@Autowired
private RedisService redisService;
@Pointcut("@annotation(com.wetran.codex.business.avoid_repetition.AFormLock)")
public void reqLock() {
}
/**
* @param point
*/
@Around("reqLock()")
public Object constructionSite(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
//获取注解
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
//目标类、方法
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
//由于使用方法名+用户ID创建的Key,,,必须要有用户id参数
Long userId = Long.parseLong(request.getParameter("id"));
log.info("防止表单重复提交类:{}. 方法:{}.用户ID:{}.", className, methodName, userId);
String key = RedisConstants.BLACKlIST_LOCK_KEY + methodName + ":" + userId;
FormLock formLock = method.getAnnotation(FormLock.class);
long timeout = formLock.timeout();
if (timeout < 0) {
//过期时间3000毫秒
timeout = 3000;
}
//校验该方法该用户的key是否存在,存在直接返回错误
if (redisService.existKey(key)) {
return RespUtils.fail("请勿重复提交");
}
boolean b = redisService.addString(key, DateUtils.getNow(), timeout, TimeUnit.MILLISECONDS);
log.info("创建锁结果:{}. key:{}.", b, key);
//执行方法
Object object = point.proceed();
//整理施工现场
Boolean aBoolean = redisService.delKey(key);
log.info("删除redis锁结果:{}.", aBoolean);
return object;
}
}
redis有效时间根据自身业务需求进行调整即可
在需要防止表单重复提交的方法上添加@FormLock注解即可,可根据不同方法指定相应的有效时间