后端防止重复点击设计

一、背景

    想了解的都懂,不再描述。

二、解决的主要思想

    重复调用会存在在以下几种情况中:

    1、点击一次后无遮罩可进行二次点击。(可通过前端进行设置)

    2、在出现遮罩之前,可能由于屏幕的特殊性,而自行进行了多次点击。(主要是避免此种问题)

    在同一时刻,调用同一个方法,且入参一致则认定为是重复点击,此时不在执行后续方法。

三、思路

    1、为了方法的通用性以及和业务系统进行解耦,在此使用aop的环绕增强。

    2、在增强中判断当前的类名+方法名+入参转换为(json)组装成的key是否已经在redis中存在

    3、利用redis的setNx(此方法为原子性,不建议判断后再进行set,避免出现线程安全问题)

    4、返回为true,则说明未提交。调用pjp.proceed方法执行。

        4.1、方法执行后删除当前redis值

    5、返回为false,则说明为重复点击,则直接返回。

四、代码实现

    1、定义注解类

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ForbidRepeatClick { }

    2、定义切面

    @Component
    @Aspect
    @Order(1)
    public class ForbidRepeatClickInterceptor {
        private static final Logger LOGGER = LoggerFactory.getLogger(ForbidRepeatClickInterceptor.class);
        @Pointcut("@annotation(ForbidRepeatClick)")
       public void pointcut() {
       }
        @Around("pointcut()")
        public Object forbidRepeatClick(ProceedingJoinPoint pjp) throws Throwable {
            //1、根据入参方法名获取组装的redis的key值
            String redisKey = getRedisKey(pjp);
            LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:{}", redisKey);
           
            if(RedisUtil.setIfAbsent(redisKey, "exist")) {
                LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:notexist");
                //2、当前方法同一时间段无完全同参数调用,则继续往下执行
               Object res = pjp.proceed();
                //2.1 执行后将数据从redis删除
                RedisUtil.delete(redisKey);
                return res;
            }
        
           //3、当前方法同一时间段具有相同参数执行,则不再执行,直接返回错误标识
           LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:exist");
           CommonResponse commonResponse = new CommonResponse();
           commonResponse.setCode(ResultEnum.REPEAT_CLICK.getNo());
           return commonResponse;      
       }
    
        /**
         * 获取存储的redis的key值
         * @param pjp
         * @return
         */
        private String getRedisKey(ProceedingJoinPoint pjp) {
           
            // 1、获取被代理的对象类型
            String className = pjp.getTarget().getClass().getName();
            
            // 2、获取当前代理的方法名
           String methodName = pjp.getSignature().getName();
           
            // 3、获取入参并转换成jason串
            String convertJson = convertArgsToJson(pjp.getArgs());
           
            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(JSON.toJSONString(object));
               }
            }
           return convertJson.toString();
        }

 

注:本次设计主要是利用到了redis是线程安全的以及redis进行处理分布式问题。

方法返回值的设计在此不再赘述,如果后端方法使用的是同类型的返回值,可直接返回该类型,如果不同类型,请参考策略模式进行设计。

请注意方法调用捕获异常时的返回值。(如果设计时有问题,可以私聊博主哦)

aop失效请参考链接:后续补充。~~

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java后端大转盘开发是一种基于Java语言的后端技术,主要用于实现大转盘游戏的业务逻辑和功能。在开发过程中,需要使用Java开发工具和框架进行编码,以实现用户在页面上进行抽奖的功能。 首先,需创建大转盘的数据模型。该模型包括转盘上的奖品信息,如奖品的名称、图片、概率等。这些数据可以存储在数据库中,以便后续从数据库中读取和处理。 接下来,需要使用Java技术实现抽奖逻辑。可以使用随机数生成器来实现抽奖过程,通过设定奖品的概率来决定用户中奖的机会。当用户点击抽奖按钮时,后端代码会生成一个随机数,并与每个奖品的中奖概率进行比较,确定用户所中的奖品,并返回给前端。 此外,还需要考虑并发情况下的线程安全性。在高并发的情况下,需要使用线程同步技术,如互斥锁或信号量,来保证同时只有一个用户能够进行抽奖操作,避免重复计算和结果错乱。 另外,还需要对用户的抽奖次数进行限制,防止恶意用户滥用系统资源。可以在后端实现限制逻辑,如每个用户每天只能抽奖一次,或者允许用户积累一定的次数后再进行抽奖。 最后,还可以考虑将奖品的中奖记录保存在数据库中,便于后续查看和统计。可以记录用户的中奖信息、抽奖时间等,以便进行后续的数据分析和运营。 总结起来,Java后端大转盘开发需要涉及数据模型设计、业务逻辑编码、随机数生成、线程同步和用户限制等方面的技术,以实现抽奖功能。这项技术要求开发者熟悉Java编程语言和相关的开发框架,能够灵活地运用各类技术实现一个稳定、高效的大转盘系统。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值