实战篇(一)BitMap实现签到功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


项目背景

现要求实现一个签到功能,要求如下:

  • 能够判断用户是否已经进行签到
  • 能够判断用户连续签到的天数

1、理论讲解

Bitmap是一个存储二进制数字的数组,数组中每个元素的下标被称为offset。

Bitmap 不是Redis中的实际数据类型,而是在String类型上定义的一组面向位的操作,将其视为位向量。由于字符串是二进制安全的块,且最大长度为512MB,它们适合用于设置最多 232个不同的位。

命令 介绍
SETBIT key offset value 设置指定 offset 位置的值
GETBIT key offset 获取指定 offset 位置的值
BITCOUNT key start end 获取 start 和 end 之间值为 1 的元素个数
BITOP operation destkey key1 key2 ... 对一个或多个 Bitmap 进行运算,可用运算符有 AND, OR, XOR 以及 NOT

2、实现方式

用户签到功能如下所示:

  • key的设计:"sign:" + userId + 日期(格式为yyyyMM)
  • 写入Redis中(比如当月第5天,就将Bitmap对应的第4个位置设置为1)
java 复制代码
    @Override
    public void sign() {
        // 1.获取当前登录用户
        Long userId = AuthContextUtil.getUserInfo().getId();
        System.out.println(userId);
        // 2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        // 3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = "sign:" + userId + keySuffix;
        // 4. 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        // 5. 写入Redis SETBIT key offset 1
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
    }

统计今天截止的连续签到次数:

  • key的设计:"sign:" + userId + 日期(格式为yyyyMM)相同业务下格式保持一致
  • 获取本月为止的所有签到记录,返回的是一个十进制的数字
  • 该数字的二进制形式的最低位代表的是今天签到的情况,最高位代表着是当月第一天的签到情况。
  • 获取当月至今为止的签到情况,只需要从低位到高位以此与1做位运算即可,直到为0,即为断签。
java 复制代码
public int signCount() {
        // 1.获取当前登录用户
        Long userId = AuthContextUtil.getUserInfo().getId();
        // 2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        // 3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = "sign:" + 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 0;
        }

        Long num = result.get(0);
        if(num == null || num == 0){
            return 0;
        }
        int count = 0;
        // 6. 循环遍历
        // 如果为0,说明未签到,结束
        // 如果不为0,说明已签到,计数器+1
        while ((num & 1) != 0) {
            // 6.1. 让这个数字与1做与运算,得到数字的最后一个bit位,判断这个bit位是否为0
            count++;
            num >>>= 1;
            // 把数字右移一位,抛弃最后一个bit位,继续下一个bit位
        }
    return count;
    }

总结

BitMap因其结构的特殊性,所以十分适合做用户签到的功能。

相关推荐
都叫我大帅哥7 小时前
Java JJWT 完全指南:从入门到生产级实践
java
前端开发张小七9 小时前
Java 学习笔记 · 第一课:基础语法与核心概念
java·后端
凡尘——雨落凡尘9 小时前
PHP 线上十大隐形故障复盘:90% 的网站卡顿、502、雪崩,都是这些细节导致的
redis·nginx·php·session
ThsPool9 小时前
【ENVI二次开发学习整理 04】ENVI功能扩展与二次开发
java·前端·javascript
赤壁小虾10 小时前
【渲染流水线】[逐片元阶段]-[透明度测试]以UnityURP为例
java·前端·数据库
青山木11 小时前
Hot 100 --- 搜索插入位置
java·数据结构·算法·leetcode
Jul1en_11 小时前
【Claude Code Compact】源码级别的学习上下文压缩
java·前端·学习·github·ai编程
摇滚侠11 小时前
《SpringBoot 3:入门与应用实战》第 15 章 生产级特性 管理 Spring Boot 应用 阅读笔记
java·spring boot·笔记
XWalnut11 小时前
SpringBoot快速入门
java·spring boot·后端
前端 贾公子11 小时前
第06章:结构化输出 (上)
java·服务器·前端