用户签到
- BitMap用法
- 签到功能
- 签到统计
BitMap用法:
我们按月来统计用户签到信息,签到记录为1,未签到则记录为0.(布隆过滤器就是采用这种结构)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RsaZg9D6-1669736765619)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20221129181234928.png)]](https://img-blog.csdnimg.cn/378bb1d02f0a4dc682300f56ecf0ef35.png)
把每一个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中
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9vsPG5i8-1669736765621)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20221129212906306.png)]](https://img-blog.csdnimg.cn/35023038bced445d960bb1db0fa15cd1.png)
提示:因为BitMap底层是基于String数据结构,因此其操作也都封装在字符串相关操作中了。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0TxiynJ-1669736765622)(C:\Users\20745\AppData\Roaming\Typora\typora-user-images\image-20221129213015824.png)]](https://img-blog.csdnimg.cn/f52d30ef120349ef81eb2a77b0ed31a5.png)
代码实现
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);
}








![[思维模式-5]:《如何系统思考》-1- 认识篇 - 总体结构与知识框架](https://img-blog.csdnimg.cn/89d4c9d199e44ea8bad08cbc06aa5881.png)



![[附源码]计算机毕业设计springboot个性化产品服务管理系统论文](https://img-blog.csdnimg.cn/6cb1f3f191a34072a0cbd772f4d59631.png)






