仿黑马点评项目(七、用户签到 BitMap)

1. BitMap用法

用Redis的BitMap来映射签到情况,Redis找那个利用String类型数据结构实现BitMap,因此最大上限是512M,转换为bit则是2^32bit位。

Redis中BitMap的常用指令:

  • SETBIT:向指定位置(offset)存入一个0或1
  • GETBIT :获取指定位置(offset)的bit值
  • BITCOUNT :统计BitMap中值为1的bit位的数量
  • BITFIELD :操作(查询、修改、自增)BitMap中bit数组中的指定位置(offset)的值
  • BITFIELD_RO :获取BitMap中bit数组,并以十进制形式返回
  • BITOP :将多个BitMap的结果做位运算(与 、或、异或)
  • BITPOS :查找bit数组中指定范围内第一个0或1出现的位置

常用指令注意点:

  • 注意SETBIT的offset是从0开始!像key第一个位置存入一个0,指令是 SETBIT key 0 0
  • 关于BITFIELD中[GET type offset]:
    • type的字母符号是表示返回结果的有无符号,u表示无符号,i表示有符号,第一位bit就是符号位
    • type的数字表示从offset开始操作多少比特位,也就是说BITFIELD可以进行多比特位操作
    • GET u3 0:返回BITMAP的前三位十进制的结果

2. 签到功能

  • 用户需求
/**
 * 用户签到
 * */
@Override
public Result sign() {
    // 1.获取当前登录用户
    Long userId = UserHolder.getUser().getId();
    // 2.获取日期
    LocalDateTime now = LocalDateTime.now();
    // 3.拼接key
    String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
    String key = USER_SIGN_KEY + userId + keySuffix;
    // 4.获取今天是本月的第几天
    int dayOfMonth = now.getDayOfMonth();
    // 5.写入Redis SETBIT key offset 1
    stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
    return Result.ok();
}
  • 测试的话可以用postman,不过需要先设置请求头的token,利用url签到;也可以直接使用Redis的命令行进行签到。

3. 签到统计

  • 什么叫做连续签到天数:从最后一次签到开始向前统计,直到遇到第一次未签到为止,计算总的签到次数,就是连续签到的天数。
    1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1

  • 如何得到本月到今天为止的所有签到数据?
    Redis指令:BITFIELD key GET u[dayOfMonth] 0,该条指令返回的数据是十进制的

  • 如何从后向前遍历每个bit位?
    只需要让得到的10进制数字和1做与运算就可以了,因为1只有遇见1 才是1,其他数字都是0 ,我们把签到结果和1进行与操作,每与一次,就把签到结果向右移动一位,依次内推,我们就能完成逐个遍历的效果了。

  • 需求实现:

/**
* 统计连续签到天数
*/
@Override
public Result signCount() {
   // 1.获取当前登录用户
   Long userId = UserHolder.getUser().getId();
   // 2.获取日期
   LocalDateTime now = LocalDateTime.now();
   // 3.拼接key
   String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
   String key = USER_SIGN_KEY + userId + keySuffix;
   // 4.获取今天是本月的第几天
   int dayOfMonth = now.getDayOfMonth();
   // 5.获取本月截止今天为止的所有的签到记录,返回的是一个十进制的数字 BITFIELD sign:5:202203 GET u14 0
   List<Long> result = stringRedisTemplate.opsForValue().bitField(
           key,
           BitFieldSubCommands.create()
                   .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
   );
   if (result == null || result.isEmpty()) {
       // 没有任何签到结果
       return Result.ok(0);
   }
   Long num = result.get(0);
   if (num == null || num == 0) {
       return Result.ok(0);
   }
   // 6.循环遍历
   int count = 0;
   while (true) {
       // 6.1.让这个数字与1做与运算,得到数字的最后一个bit位  // 判断这个bit位是否为0
       if ((num & 1) == 0) {
           // 如果为0,说明未签到,结束
           break;
       }else {
           // 如果不为0,说明已签到,计数器+1
           count++;
       }
       // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位
       num >>>= 1;
   }
   return Result.ok(count);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值