黑马点评--用户签到

用户签到

  • BitMap用法
  • 签到功能
  • 签到统计

BitMap用法:

我们按月来统计用户签到信息,签到记录为1,未签到则记录为0.(布隆过滤器就是采用这种结构)

黑马点评--用户签到_第1张图片

把每一个bit位对应当月的每一天,形成了映射关系。用0和1标示业务状态,这种思路就称为位图(BitMap)。

Redis是利用string类型数据结构实现BitMap,因此最大上限512M,转换为bit则是2^32个bit位。

BitMap的操作命令有:‘

SETBIT:向指定位置(offset)存入一个0或1

GETBIT:获取指定位置(offset)的bit值

BITCOUNT:统计BitMap中值为1的bit位

BITFIELD:操作(查询,修改,自增)BitMap中bit数组中的指定位置(offset)的值

BITFIELD_RD:获取BitMap中bit数组,并以十进制形式返回

BITOP:将多个BitMap的结果做位运算(与,或,异或)

BITPOS:查找bit数组中指定范围内第一个0或1出现的位置

签到功能

需求:实现签到接口,将当前用户当天签到信息保存到Redis中

黑马点评--用户签到_第2张图片

提示:因为BitMap底层是基于String数据结构,因此其操作也都封装在字符串相关操作中了。

黑马点评--用户签到_第3张图片

代码实现

  public Result sign() {
        //1.获取当前登录的用户
        Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyy-MM"));
        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();
    }

统计连续签到

什么叫连续签到天数?

从最后一次签到开始向前统计,直到遇到第一次未签到为止,计算总的签到次数,就是连续签到天数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BTQliNoL-1669736765623)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20221129225245656.png)]

如何得到本月到今天为止的所有签到数据?

BITFELD key GET u[dayOfMonth]0

如何从后向前遍历每一个bit位?

与1做运算,就能得到最后一个bit位

随后右移1位,下一个bit为就成为最后一个bit为。

代码实现:

public Result signCount() {
        //1.获取当前登录的用户
        Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyy-MM"));
        String key=USER_SIGN_KEY+userId+keySuffix;
        //4.获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5.获取本月截止今天为止的所有的签到记录,返回的是一个十进制的数字
        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();
        }
        //6.循环遍历
        int count=0;
        while (true) {
            //6.1让这个数字与1做与运算,得到数字的最后一个bit位//判断这个bit是否为0
            if ((num & 1) == 0){
                //如果为0,说明未签到,结束
                break;
            }
            //如果不为0,说明已签到,计数器+1
                count++;
            //把数字右移一位,抛弃最后一个bit位,继续下一个bit位
            num=num >>1;
        }
        return Result.ok(count);
    }

你可能感兴趣的:(Java,redis,java,nosql)