刷题系统重构--添加vip功能

c端系统往往都具有vip功能作为主要盈利点,那咱们的刷题微服务系统肯定也该有,但是系统设计的时候就没有vip系统,今天构思了一下如何设计VIP功能同时减少代码原有改动。

1.首先,我拥有一张题目信息表,和对应题目类型的答案表,为了不改动原有基础,我们新增

首先,根据原料的题目表建一张vip题目表,可以用来只存储vip题目,或者0,1区分vip题目,重构了一下新增题目,加了一项添加题目的vip字段的添加

 ,这样,在不影响原有代码的基础上,我们便有了vip题目的设计,而且这个方法我们选择了题目列表可获取,题目详情不可获取,不影响原有题目浏览页面观感,同时也利于客户了解到系统题目丰富,只是缺少vip,更加提高了用户的信赖。

所以我们只需要重构题目详情返还页即可,将vip字段返还便可以判断是否vip题目。

这样vip的返还我们就有了

但是后来,我又想到了问题,假如说这样传输的话,非vip用户查询题目详情,其实只需要知道什么题是vip,什么题不需要可以看,但是我这样的基础重构导致题目详细信息依旧会传递给前端,所以也会面临泄露的风险。

于是我重新根据现有代码再次修改了一下方案

用户充值vip或者刷新后会执行getPermissionNow接口获取最新权限存入redis中,之后用户进行vip题目查看时,首先通过gRpc远程调用获取是否vip信息

然后题目不进行详细题目查询将题目id传入VIP表,判断vip字段是否激活,如若不匹配,直接返还vio题目,减少不必要的网络消耗。

 

 由于系统是微服务的形式,用户作为一个单独的模块,那么我们到底是应该怎么来对vip身份进行判断,同时还能保证高并发情景下优化效率呢?

  @Override
    public List<String> getPermissionNow(String userName) {
        String permissionKeyDel = authPermissionPrefix + "." + userName;
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, userName);
        Boolean status = redisUtil.del(permissionKeyDel);  // 使用 delete 方法
        AuthUser authUser = authUserService.queryByUserName(userName);
        AuthUserRole authUserRole = authUserRoleDao.queryByUserId(authUser.getId());
        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(authUserRole.getRoleId());
        List<AuthRolePermission> rolePermissionList = authRolePermissionService.
                queryByCondition(authRolePermission);

        List<Long> permissionIdList = rolePermissionList.stream()
                .map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        //根据roleId查权限
        List<AuthPermission> permissionList = authPermissionService.queryByRoleList(permissionIdList);
        redisUtil.set(permissionKey, new Gson().toJson(permissionList));
        String permissionValue = redisUtil.get(permissionKey);
        if (StringUtils.isBlank(permissionValue)) {
            return Collections.emptyList();
        }
        // 从 Redis 中取出的数据类型应为 List<String>
        List<AuthPermission> permissionList1 = new Gson().fromJson(permissionValue,
                new TypeToken<List<AuthPermission>>() {
                }.getType());
        List<String> authList = permissionList1.stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());

        return authList;
    }

rpc调用

 

  @RequestMapping("/permission/getPermissionNow")
    Result<List<String>> getPermissionNow();
 /**
     * 判断用户是否为vip
     * @return
     */
    public boolean getUserPermissionNow() {
        Result  result =  userFeignService.getPermissionNow();

        if (result.getSuccess()) {
            List<String> permissions = (List<String>) result.getData();

            return permissions.stream()
                    .anyMatch(permission -> "subject:vip".equals(permission));
        } else {
            // 处理结果不成功的情况,例如抛出异常或者返回默认值
            throw new RuntimeException("获取权限信息失败");
        }
    }

controller判断检索逻辑

 //判断用户是不是vip
            Boolean permission = userRpc.getUserPermissionNow();
            if (log.isInfoEnabled()) {
                log.info("SubjectController.permission:{}", JSON.toJSONString(permission));
            }
            SubjectInfoBO boResult = subjectInfoDomainService.querySubjectInfo(subjectInfoBO);
            if (boResult.getVip()==1 && !permission){
                return Result.fail("请先购买vip");
            }

这样,用户只需要赋予其vip权限即可行驶vip功能,同时用户前端无感刷新。

后期也可对vip表新增其他字段,如是否依旧启用,vip几级权限,后续可以尝试将其内容抽象出单独类,进行修改维护。

但是目前此重构方法依旧具有部分问题,高并发场景下,刷新用户权限这段其实是很麻烦也与数据库很多表进行了交互,风险较大,参考更多设计思路,寻找更佳的解决方式以应对高并发场景下用户的vip权限划分

posted @ 2024-09-30 18:00  橘子味芬达水  阅读(8)  评论(0编辑  收藏  举报