BitMap实现签到功能

本文介绍了如何在Java应用中,通过Redis实现用户签到的功能,包括用户单次签到、连续签到统计以及获取用户的签到历史记录。服务层利用Redis的bitfield操作来存储和检索签到状态。
摘要由CSDN通过智能技术生成

需求:利用redis实现签到的3个功能:用户签到、连续签到统计、获取签到情况。

controller层:
/**
 * 用户签到
 * @return
 */
@PostMapping("/sign")
public Result sign(){
    return userService.sign();
}

/**
 * 连续签到统计
 * @return
 */
@GetMapping("/sign/count")
public Result signCount(){
    return userService.signCount();
}

/**
 * 获取签到情况
 * @return
 */
@GetMapping("/sign/info")
public Result signInfo(){
    return userService.signInfo();
}

service实现层:
/**
 * 用户签到
 * @return
 */
@Override
public Result sign() {
    //获取当前登录用户
    Long userId = UserHolder.getUser().getId();
    //组装key sign:userId:202401
    LocalDateTime now = LocalDateTime.now();
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + keySuffix ;
    //存入redis 执行签到
    int dayOfMonth = now.getDayOfMonth();//这个月的第几天
    redisTemplate.opsForValue().setBit(key,dayOfMonth-1,true);
    return  Result.ok();
}

/**
 * 连续签到统计
 * @return
 */
@Override
public Result signCount() {
    //1.获取当前用户
    Long userId = UserHolder.getUser().getId();
    //2.获取本月开始到目前为止的签到数据(10进制)
    LocalDateTime now = LocalDateTime.now();
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + keySuffix ;
    //2,1获取当前天数
    int dayOfMonth = now.getDayOfMonth();
    //2.1获取签到数据 返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0 获取从0号角标开始 忽略符号一共获取14位
    List<Long> longs = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create()
            .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))//当前天数
            .valueAt(0)
    );
    //健壮性判断
    if (longs == null || longs.isEmpty()) {
        // 没有任何签到结果
        return Result.ok(0);
    }
    //获取10进制数 集合第一个
    Long num = longs.get(0);
    if (num == null || num == 0){
        // 没有任何签到结果
        return Result.ok(0);
    }
    //3.循环进行与运算和计算器
    int signCount = 0;
    while (true){
        if((num & 1) == 0){
            // 如果为0,说明未签到,结束
            break;
        }else {
            //如果不为0,说明已签到,计数器+1
            signCount++;
        }
        // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位
        num >>>= 1;
    }
    return  Result.ok(signCount);
}


/**
 * 获取签到情况
 * @return
 */
@Override
public Result signInfo() {
    //1.获取当前用户
    Long userId = UserHolder.getUser().getId();
    //2.获取本月开始到目前为止的签到数据(10进制)
    LocalDateTime now = LocalDateTime.now();
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + keySuffix ;
    //2,1获取当前天数
    int dayOfMonth = now.getDayOfMonth();
    //2.1获取签到数据 返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0 获取从0号角标开始 忽略符号一共获取14位
    List<Long> longs = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create()
            .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))//当前天数
            .valueAt(0)
    );
    //健壮性判断
    if (longs == null || longs.isEmpty()) {
        // 没有任何签到结果
        return Result.ok(0);
    }
    //获取10进制数 集合第一个
    int num = longs.get(0).intValue();
    if (num == 0){
        // 没有任何签到结果
        return Result.ok(0);
    }

    //角标
    int index = dayOfMonth-1;
    //byte集合
    Byte[] arr = new Byte[dayOfMonth];
    //2.处理记录
    while (index >= 0){
        arr[index] =  (byte) (num & 1);
        //角标-1
        index--;
        //num右移1位
        num = num >>> 1;
    }

    log.info("签到记录:{}",Arrays.toString(arr));
    //3.返回
    return Result.ok(arr);
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值