AOP + Redis to prevent repeated submission of forms (annotation method)

  • Introduce SpringAOP
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • Configure redis and create redis tool class

               The redis configuration is skipped here

@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;
        }
    }
}
  • Create annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FormLock {

    /**
     * 指定时间内不可重复提交,单位毫秒
     * @return
     */
    long timeout() default 3000;

}
  • Create AOP surround notification processing class
@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;
    }
}

The effective time of redis can be adjusted according to your own business needs

Just add @FormLock annotation to the method that needs to prevent repeated submission of the form, and the corresponding effective time can be specified according to different methods

Guess you like

Origin blog.csdn.net/qq_42407917/article/details/100151015