java多层if else嵌套语句的优化思路,滑动验证码防刷功能开发

阿里巴巴java开发手册里面,在控制语句部分有一个推荐,如下:

【推荐】表达异常的分支时,少用 if-else 方式,这种方式可以改写成:

if (condition) { 
    ...

    return obj; 
}

// 接着写 else 的业务逻辑代码;

【强制】说明:如果非得使用 if()...else if()...else...方式表达逻辑,避免后续代码维护困难,请勿超过 3 层。
正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现, 其中卫语句示例如下:

public void today() { 
    if (isBusy()) {
       System.out.println(“change time.”); 
       return;

    }

    if (isFree()) {
       System.out.println(“go to travel.”);
       return; 
    }

   System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);

}

以上是手册里面完整的说明,if else的嵌套,强制不让超过三层,超过了就是程序员代码写的有问题了,需要优化。

下面我通过一段代码来进行优化多层if else嵌套问题,问题场景是投票功能,需要调腾讯云的滑动验证码来进行防止刷票(这里开启滑动验证码防刷票是需要购买的),滑动验证码是前端直接调中台接口的,中台会返回一个ticket值,然后这这边需要判断ticket值是否正确,这是投票的时候进行滑动验证码判断的逻辑。

首先这个功能做的方式是,小程序一开始加载投票活动的时候,就会返回一个字段告诉是否开启了滑动验证码,前端根据这个字段,如果开启了那么调中台的滑动验证码拿ticket,调微信接口的滑动验证码,用户滑动之后访问接口,后端判断ticket等。(因为滑动验证码在很多地方都会需要用到,所以放在了中台),多层嵌套代码如下:


public void checkSlideCaptchaRemainTimes(String activityId, String ticket, UserIp userIp)
            throws NoSuchAlgorithmException, InvalidKeyException, UnirestException {

        Activity activity = activityService.findByid(activityId);
        SlideCaptcha slideCaptcha = slideCaptchaService.findSlideCaptchaByBuserId(activity.getBUserId());

        if (activity != null){
            // 如果滑动验证码没有开启,那么不需要管滑动验证码逻辑;如果滑动验证码开启了,走如下逻辑
            if (StringUtils.isNotEmpty(ticket)){
                // 滑动验证码开启了
                if (!activity.getDisablePicvcode()) {

                    if (slideCaptcha != null) {
                        // 剩余滑动验证码次数足够
                        if (slideCaptcha.getRemainTimes() > 0) {
                                // 滑动验证码次数减1
                            slideCaptchaService.updateSlideCaptchaByBUserId(activity.getBUserId(), -1);
                                // 调中台接口确定ticket是否正确
                                slideCaptchaManager.checkTicket(ticket);

                            // 剩余次数少于100次,给用户发短信
                            if (slideCaptcha.getRemainTimes() == 300){
                                BUser bUser = userService.getBUserPhone(slideCaptcha.getBUserId());
                                executor.execute(() -> smsManager.smsSendMessage(bUser.getPhone(), slideCaptcha.getRemainTimes().toString(), "2024"));
                            }

                        } else {
                            // 将此用户的所有投票活动全部关闭滑动验证码功能
                            activityRepositoryImpl.updateActivitySlideCaptchaByBUserId(activity.getBUserId());
                            throw new BaseException(ExceptionCode.SLIDE_CAPTCHA_NOT_ENOUGH);

                        }
                    } else {
                        throw new BaseException(ExceptionCode.SLIDE_CAPTCHA_NOT_ENOUGH);

                    }
                } else {
                    // 滑动验证码关闭了
                    throw new BaseException(ExceptionCode.SLIDE_CAPTCHA_NOT_ENOUGH);

                }
            }


        } else {
          // 滑动验证码开启了但是没有传需要验证的ticket
         throw new BaseException(ExceptionCode.VOTE_SLIDE_CAPTCHA_IS_OPEN); 
        }
    }

 

看到这些代码,头都是大的,光是理解就需要半天。下面就来着手优化一下这段代码,

首先考虑问题需要考虑一些极端情况(这是一个非常好的习惯,一个人严不严谨往往就在这),比如:

1.活动一开始没有滑动验证码,然后用户投票之前,后端改成了需要滑动验证码;

这种情况为了防止用户刷票,肯定是不能让他正常投票了,刷票一般都是直接调接口的方式,所以后台需要返回一个错误码告诉前端,需要滑动验证码,不能投票,那么这个接口调用失败,前端拉取滑动验证码重新传ticket再调接口。这里可能会有人说接口调用很多次,但是没有关系,因为这个操作原本就是很少概率下的操作。

2.活动一开始就有滑动验证码,但是用户投票之前,后端改成了不需要滑动验证码;

这种情况,也许正常会想,给前端返回个错误码告诉前端:不需要滑动验证码啦!但是再仔细一想其实没有必要,因为从业务角度看,用户是需要正常投票的,不需要滑动验证码就没有了防止刷票功效,让他调用一次滑动验证码损失不大,原本滑动验证码就很便宜,所以此时直接让他正常投票就可以。

优化后的代码如下:

public void checkSlideCaptchaTicket(Activity activity, String ticket, UserIp userIp)
            throws UnirestException {

        // 如果滑动验证码没有开启,直接返回不需要做任何处理
        if (activity.getDisablePicvcode()) {
            return;
        }

        // 滑动验证码开启了,但是没有传ticket
        if (StringUtils.isEmpty(ticket)){
            throw new BaseException(ExceptionCode.VOTE_SLIDE_CAPTCHA_IS_OPEN);
        }

        SlideCaptcha slideCaptcha = slideCaptchaService.findSlideCaptchaByBuserId(activity.getBUserId());

        // 防止户没有开启过滑动验证码,但是活动中数据有误
        if (slideCaptcha == null){
            throw new BaseException(ExceptionCode.SLIDE_CAPTCHA_NOT_ENOUGH);
        }

        // 剩余滑动验证码次数足够
        if (slideCaptcha.getRemainTimes() > 0) {

            slideCaptchaService.updateSlideCaptchaByBUserId(activity.getBUserId(), -1);
            slideCaptchaManager.checkTicket(ticket);

            // 剩余次数少于100次,给用户发短信
            if (slideCaptcha.getRemainTimes() == 300){
                BUser bUser = userService.getBUserPhone(slideCaptcha.getBUserId());
                executor.execute(() -> smsManager.smsSendMessage(bUser.getPhone(), slideCaptcha.getRemainTimes().toString(), "2024"));
            }

        } else {
            // 将此用户的所有投票活动全部关闭滑动验证码功能
            activityRepositoryImpl.updateActivitySlideCaptchaByBUserId(activity.getBUserId());
            // 并发进来可能会出现一个人投票失败,但是业务上允许他成功,所以没有必要抛出异常
            // throw new BaseException(ExceptionCode.SLIDE_CAPTCHA_NOT_ENOUGH);

        }

    }

优化的地方:

1.嵌套语句改成了阿里巴巴推荐的方式,让人很容易看懂

2.减少了一次活动查询,以及减少了没有开启滑动验证码的情况下,对用户滑动验证码的查询

滑动验证码的调用思路如下:

先请求中台,中台返回数据,也就是腾讯云那边的滑动验证码

前端根据返回的地址,校验滑动验证码是否滑正确

这是图片没有对准的返回值,图片对准了ticket就会是一个值 如这种:往往是加密过的值

Xd0Wt2g7ZFa-MX5qE0dSA1j-SOkbJWLl7uLUNMEl2DUaAuPsGPT0mZGaaIS_Xv7X2dYTlgj00CQ*

发布了30 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40898368/article/details/102946014